前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP核心技术与最佳实践 读书笔记 第一章面向对象思想的核心概念

PHP核心技术与最佳实践 读书笔记 第一章面向对象思想的核心概念

作者头像
lilugirl
发布2019-05-26 20:23:58
1.1K0
发布2019-05-26 20:23:58
举报
文章被收录于专栏:前端导学前端导学

第一章 面向对象思想的核心概念

面向对象程序设计是一种程序设计范型,同时也是一种程序开发方法。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性,灵活性和可扩展性。

{函数式编程 如LISP ,

命令式编程 { 面向过程, 面向对象}

}

1.1面向对象的“形”与“本”

类是对象的抽象组织,对象是类的具体存在。

1.1.1对象的“形”

代码语言:javascript
复制
class person{
   public $name;
   public $gender;
   public function say(){
   echo $this->name," is ",$this->gender;
   }
}

$student=new person();
$student->name="Tom";
$student->gender='male';
$student->say();
$teacher=new person();
$teacher->name='Kate';
$teacher->gender='female';
$teacher->say();
print_r((array)$student);
var_dump($student);

$str=serialize($student);
echo $str;
file_put_contents('store.txt',$str);

$str=file_get_contents('store.txt');
$student=unserialize($str);
$student->say();

所谓序列化,就是把保存在内存中的各种对象状态(属性)保存起来,并且在需要时可以还原出来。

对象序列化后,存储的只是只是对象的属性。 对象就是数据,对象本身不包含方法。但是对象有一个“指针”指向一个类,这个类里可以有方法。

序列化和反序列化时都需要包含类的对象的定义,否则可能返回不正确的结果。

1.1.2 对象的“本”

代码语言:javascript
复制
#zend/zend.h
typedef union_zvalue_value{
  long lval;
  double dval;
  struct{
     char *val;
	 int len;
  } str;
  HashTable *ht;
  zend_object_value obj;

} zvalue_value;


#zend/zend.h
typedef struct_zend_object{
  zend_class_entry *ce;
  HashTable *properties;
  HashTable *guards;
} zend_object;

对象是一种很普通的变量,不同的是其携带了对象的属性和类的入口。

1.1.3 对象与数组

代码语言:javascript
复制
$student_arr=array('name'=>'Tom','gender'=>'male');
echo "\n";
echo serialize($student_arr);

对象和数组的区别在于:对象还有个指针,指向了它所属的类。

1.1.4 对象与类

代码语言:javascript
复制
class person{
  public $name;
  public $gender;
  public function say(){
  echo $this->name,"\tis ",$this->gender,"\r\n";
  }
}

class family{
  public $people;
  public $location;
  public function __construct($p,$loc){
      $this->people=$p;
	  $this->location=$loc;
  }
}

$student=new person();
$student->name='Tom';
$student->gender='male';
$student->say();
$tom=new family($student,'peking');

echo serialize($student);
$student_arr=array('name'=>'Tom','gender'=>'male');
echo "\n";
echo serialize($student_arr);
print_r($tom);
echo "\n";
echo serialize($tom);

当一个对象的实例变量应用其他对象时,序列化该对象时也会对引用对象进行序列化。

1.2 魔术方法的应用

语法糖:指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法。 如魔术方法的写法。

1.2.1 __set和__get方法

代码语言:javascript
复制
class Account{
   private $user=1;
   private $pwd=2;
   public function __set($name,$value){
      echo "Setting $name to $value \r\n";
	     $this->$name=$value;
   }
   public function __get($name){
       if(!isset($this->$name)){
	       echo '未设置';
		   $this->$name='正在为你设置默认值';
	   }
	   return $this->$name;
   }
}


$a=new Account();
echo $a->user;
$a->name=5;
echo $a->name;
echo $a->big;

PHP一个类中只允许有一个构造函数。

PHP中的“重载”是指动态地“创建”类属性和方法。__set和__get方法被归到重载里。

定义了__get和__set方法,直接调用私有属性 和在对外的public方法中操作private属性 的原理一样,只不过操作起来更简单。

1.2.2 __call 和__callStatic方法

代码语言:javascript
复制
class Account{
  
   public function __call($name,$arguments){
      switch(count($arguments)){
	       case 2:
		     echo $arguments[0]*$arguments[1],PHP_EOL;
		     break;
		   case 3:
		     echo array_sum($arguments),PHP_EOL;
			 break;
		   default:
		     echo '参数不对',PHP_EOL;
			 break;
		   
	  }
   }
}


$a=new Account();

echo $a->make(5);
echo $a->make(5,6);
echo $a->make(5,6,7);
代码语言:javascript
复制
abstract class ActiveRecord{
    protected static $table;
	protected $fieldvalues;
	public $select;
	
	static function findById($id){
	   $query="select * from "
	   .static::$table
	   ." where id=$id";
	   return self::createDomain($query);
	     
	}
	
	function __get($fieldname){
	   return $this->fieldvalues[$fieldname];
	}
	
	
	static function __callStatic($method,$args){
	   $field=preg_replace('/^findBy(\w*)$/','${1}',$method);
	   $query="select * from "
	   .static::$table
	   ." where $field='$args[0]'";;
	   return self::createDomain($query);
	   
	   
	}
	
	
	private static function createDomain($query){
	   $klass=get_called_class();
	   $domain=new $klass();
	   $domain->fieldvalues=array();
	   $domain->select=$query;
	   foreach($klass::$fields as $field=>$type){
	       $domain->fieldvalues[$field]='ATODO: set from sql result';
	   }
	   return $domain;
	}
	
}

class Customer extends ActiveRecord{
    protected static $table='custdb';
	protected static $fields=array(
	'id'=>'int',
	'email'=>'varchar',
	'lastname'=>'varchar',
	);

}

class Sale extends ActiveRecord{
   protected static $table='salesdb';
   protected static $fields=array(
      'id'=>'int',
	  'item'=>'varchar',
	  'qty'=>'int'
   );
   
}
echo Customer::findById(111)->select;
echo Customer::findById(111)->email;
echo Customer::findByLastname('liu')->select;

1.2.3 __toString 方法

只有实现了__toString方法才能直接echo 对象。

代码语言:javascript
复制
class Account{
  public $user=1;
  public $pwd=2;
  
  public function __toString(){
      return "当前对象的用户是{$this->user},密码是{$this->pwd}";
  }
}
$a=new Account();
echo $a;

echo PHP_EOL;
print_r($a);

1.3 继承与多态

继承是类级别的复用,多态是方法级别的复用。

1.3.1 类的组合与继承

代码语言:javascript
复制
class person{
   public $name='Tom';
   public $gender;
   static $money=10000;
   public function __construct(){
      echo '这里是父类',PHP_EOL;
   }
   public function say(){
      echo $this->name,"\t is ",$this->gender,"\r\n";
   }
}

class family extends person{
   public $name;
   public $gender;
   public $age;
   static $money=100000;
   public function __construct(){
      parent::__construct();
	  echo '这里是子类',PHP_EOL;
   }
   
   public function say(){
      parent::say();
	  echo $this->name,"\t is \t",$this->gender,", and is \t",$this->age,PHP_EOL;
	  
   }
   
   public function cry(){
      echo parent::$money,PHP_EOL;
	  echo '%>_<%',PHP_EOL;
	  echo self::$money,PHP_EOL;
	  echo '(*^-^*)';
   }
}

$poor=new family();
$poor->name='Lee';
$poor->gender='female';
$poor->age=25;
$poor->say();
$poor->cry();

从这个例子可以看出 父类直接共享了子类的成员值。 在开发时,设置最严格的报错等级,在部署时可适当降低。

低耦合指模块与模块之间,尽可能地使模块间独立存在;模块与模块之间的接口尽量少而简单。

解耦是要解除模块与模块之间的依赖。

继承和组合均可的情况下,倾向用组合。

继承破坏封装性。继承是紧耦合的。继承扩展复杂。不恰当地使用继承可能违反现实世界中的逻辑。

底层代码多用组合,顶层、业务层代码多用继承。底层用组合可以提高效率,避免对象臃肿。顶层代码用继承可以提高灵活性,让业务更方便。

多重继承:一个类可以同时继承多个父类,组合两个父类的功能。 PHP中的Traits既可以使单继承模式的语言获得剁成继承的灵活,有可以避免多重继承带来的种种问题。

代码语言:javascript
复制
class car{
  public function addoil(){
     echo "Sdd oil \r\n" ;
  }
  
 
}

class bmw extends car{  
}

class benz{
  public $car;
  public function __construct(){
     $this->car=new car();
  }
  
  public function addoil(){
     $this->car->addoil();
  }
}

$bmw=new bmw();
$bmw->addoil();
$benz=new benz();
$benz->addoil();

1.3.2 各种语言中的多态

重载不是面向对象里的东西,它数据域多态的一种表现形式。

多态性是一种通过多种状态或者阶段描述相同对象的编程方式。实际开发中,只要关心一个接口或者基类的编程,而不必关心一个对象所属于的具体类。

代码语言:javascript
复制
class employee{
  protected function working(){
     echo '本方法需要重载才能运行';
  }
}

class teacher extends employee{
  public function working(){
     echo '教书';
  }
}

class coder extends employee{
   public function working(){
      echo '敲代码';
   }
}

function doprint($obj){
  if(get_class($obj)=='employee'){
      echo 'Error';
  }else{
     $obj->working();
  }
}

doprint(new teacher());
doprint(new coder());
doprint(new employee());
代码语言:javascript
复制
interface employee{
  public function working();
}

class teacher implements employee{
    public function working(){
	   echo '教书';
	}
}

class coder implements employee{
   public function working(){
      echo '敲代码';
   }
}

function doprint(employee $i){
  $i->working();
}

$a=new teacher();
$b=new coder();
doprint($a);
doprint($b);

1.4 面向接口编程

1.4.1 接口的作用

接口中所有的方法都是抽象的,没有程序体。

接口的方法必须被全部实现,否则将报错。

代码语言:javascript
复制
interface mobile{
  public function run();
}

class plain implements mobile {
   public function run(){
      echo "我是飞机";
   }
   
   public function fly(){
       echo "飞行";
   }
}


class car implements mobile{
   public function run(){
     echo "我是汽车";
   }
}


class machine{
   function demo(mobile $a){
      $a->fly();
   }
}
$obj=new machine();
$obj->demo(new plain());
$obj->demo(new car());

1.4.2 对PHP接口的思考

代码语言:javascript
复制
trait Hello{
   public function sayHello(){
      echo 'Hello ';
   }
}
trait World{
   public function sayWorld(){
      echo 'World';
   }
}

class MyHelloWorld{
  use Hello,World;
  public function sayExcalamationMark(){
      echo '!';
  }
}

$o=new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExcalamationMark();

PHP中的接口没有契约限制,缺少足够多的内部接口。

1.5 反射

反射是指在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类,方法,属性等详细信息,包括注释。

这种动态获取信息以及动态调用对象方法的功能成为反射API。

1.5.1 如何使用反射API

代码语言:javascript
复制
class person{
  public $name;
  public $gender;
  public function say(){
     echo $this->name,"t is ",$this>gender,"\r\n";
  }
  
  public function __set($name,$value){
      echo "Setting $name to $value \r\n";
	  $this->$name=$value;
  }
  
  public function __get($name){
     if(!isset($this->$name)){
	    echo '未设置';
		$this->$name="正在为你设置默认值";
	 }
	 return $this->$name;
  }
  
 
}

  $student=new person();
  $student->name='Tom';
  $student->gender='male';
  $student->age=24;
代码语言:javascript
复制
$reflect=new ReflectionObject($student);
  $props=$reflect->getProperties();
  foreach($props as $prop){
      print $prop->getName()."\n";
  }
  
  $m=$reflect->getMethods();
  foreach($m as $prop){
     print $prop->getName()."\n";
  }

使用class函数,返回对象属性的关联数组以及更多的信息

代码语言:javascript
复制
//返回对象属性的关联数组
var_dump(get_object_vars($student));
  
//类属性
var_dump(get_class_vars(get_class($student)));   
   
//返回由类的方法名组成的数组
var_dump(get_class_methods(get_class($student)));

//获取对象属性列表所属的类
echo get_class($student);
代码语言:javascript
复制
//反射获取类的原型
$obj=new ReflectionClass('person');
$className=$obj->getName();
$Methods=$Properties=array();
foreach($obj->getProperties() as $v){
    $Properties[$v->getName()]=$v;
}
foreach($obj->getMethods() as $v){
    $Methods[$v->getName()]=$v;
}
echo "class {$className} \n {\n";
is_array($Properties)&&ksort($Properties);

foreach($Properties as $k=>$v){
   echo "\t";
   echo $v->isPublic()?'Public':'',
   $v->isPrivate()?'private':'',
   $v->isProtected()?'protected':'',
   $v->isStatic()?' static':'';
   echo "\t{$k}\n";
}

echo "\n";

if(is_array($Methods)) ksort($Methods);
foreach($Methods as $k=>$v){
   echo "\tfunction{$k}(){}\n";
}
echo "}\n";

1.5.2 反射有什么作用

反射可以用于文档生成,做hook实现插件功能,做动态代理。

代码语言:javascript
复制
class mysql{
  function connect($db){
     echo "连接到数据库${db[0]} \r\r";
  }
}


class sqlproxy{
  private $target;
  function __construct($tar){
     $this->target[]=new $tar();
	
	 
  }
  
  function __call($name,$args){
      foreach($this->target as $obj){
	     
	     
		  $r=new ReflectionClass($obj);
		   if($method=$r->getMethod($name)){
		       if($method->isPublic()&& !$method->isAbstract()){
			       echo "方法前拦截记录Log\r\n";
				   $method->invoke($obj,$args);
				   echo "方法后拦截\r\n";
			   }
		   }
		 
		  
		  
	  }
  }
}
$obj=new sqlproxy('mysql');

$obj->connect('member');

1.6 异常和错误处理

PHP把许多异常看作错误。

1.6.1 如何使用异常处理机制

在PHP里,遇到任何自身错误都会触发一个错误,而不是抛出异常(对于一些情况,会同时抛出异常和错误)。

代码语言:javascript
复制
$a=null;
try{
$a=5/0;
echo $a,PHP_EOL;
}catch(exception $e){
  $e->getMessage();
  $a=-1;
}
echo $a;

PHP通常是无法自动捕获有意义的异常,它把所有不正确的情况都视作错误,你要想捕获这个异常,就得使用if else 结构,保证代码是正常的,然后判断如果xxx,则手工抛出异常,再捕获。

代码语言:javascript
复制
class emailException extends exception{
   
}
class pwdException extends exception{
  function __toString(){
     return "Exception{$this->getCode()}:{$this->getMessage()} in File:{$this->getFile()} on line:{$this->getLine()}";

  }
}

function reg($reginfo=null){
   if(empty($reginfo) || !isset($reginfo)){
      throw new Exception("参数非法");
   }
   
   if(empty($reginfo['email'])){
       throw new emailException("邮件为空");
   }
   if($reginfo['pwd']!=$reginfo['repwd']){
       throw new pwdException("两次密码不一致");
   }
   echo '注册成功';

}
代码语言:javascript
复制
try{
   reg(array('email'=>'bcc@126.com','pwd'=>'abc','repwd'=>'12342'));
}catch(emailException $ee){
   echo $ee->getMessage();
}catch(pwdException $ep){
   echo $ep;
   echo PHP_EOL,'特殊处理';
}catch(Exception $e){
   echo $e->getTraceAsString();
   echo PHP_EOL,'其他情况,统一处理';
}

注意:exception作为超类应该放在最后捕获,不然捕获这个异常超类后,后面的捕获就终止了。

以下三种情景下会用到异常处理机制。

1 对程序的悲观预测 2 程序的需要和对业务的关注 异常偏重于保护业务数据一致性,并强调对异常业务的处理。

3 语言级别的健壮性要求 可以把异常造成的逻辑中断破坏降低到最小范围内,并经过补救处理后不影响业务逻辑的完整性;乱抛异常和只抛不捕获,或捕获而不补救,会导致数据混乱。

1.6.2 怎样看PHP的异常

1.6.3 PHP中的错误级别

depreccated

notice

warning

fetal error

prase error

代码语言:javascript
复制
$date='2012-12-20';
if(ereg("([0-9]{4}-([0-9]{1,2})-([0-9]{1,2})",$date,$regs)){
   echo "$regs[3].$regs[2].$regs[1]";
}else{
  echo "Invalid date format:$date";
}
if($i>5){
  echo '$i 没有初始化啊',PHP_EOL;
}

$a=array('o'=>2,3,6,8);
echo $a[o];
$result=array_sum($a,3);
echo fun();
echo '致命错误后呢,还会执行吗?'

1.6.4 PHP中的错误处理机制

代码语言:javascript
复制
function customError($errno,$errstr,$errfile,$errline){
   echo "<b>错误代码:</b>[${erron}] ${errstr}\r\n";
   echo "错误所在的代码行:{$errline} 文件{$errfile}\r\n";
   echo " PHP 版本 ",PHP_VERSION,"(",PHP_OS,")\r\n";
}
set_error_handler("customError",E_ALL|E_STRICT);
$a=array('o'=>2,3,45,6);
echo $a[o];

如果使用自定义的set_error_handler接管PHP的错误处理,@将失效,这种错误也会被显示。

可以把“异常”像错误一样使用set_error_handler接管,进而主动抛出异常,来捕获异常和非致命的错误。

代码语言:javascript
复制
function customError($erron,$errstr,$errfile,$errline){
   //自定义错误处理时,手动抛出异常
   throw new Exception($erron.'|'.$errstr);
}
set_error_handler("customError",E_ALL|E_STRICT);
try{ $a=5/0;}
catch(Exception $e){
  echo '错误信息:',$e->getMessage();
}

错误抛出

代码语言:javascript
复制
$divisor=0;
if($divisor==0){
 trigger_error("Can not  divide by zero",E_USER_ERROR);
}
echo 'break';
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第一章 面向对象思想的核心概念
    • 1.1面向对象的“形”与“本”
      • 1.1.1对象的“形”
      • 1.1.2 对象的“本”
      • 1.1.3 对象与数组
      • 1.1.4 对象与类
    • 1.2 魔术方法的应用
      • 1.2.1 __set和__get方法
      • 1.2.2 __call 和__callStatic方法
      • 1.2.3 __toString 方法
    • 1.3 继承与多态
      • 1.3.1 类的组合与继承
      • 1.3.2 各种语言中的多态
    • 1.4 面向接口编程
      • 1.4.1 接口的作用
      • 1.4.2 对PHP接口的思考
    • 1.5 反射
      • 1.5.1 如何使用反射API
      • 1.5.2 反射有什么作用
    • 1.6 异常和错误处理
      • 1.6.1 如何使用异常处理机制
      • 1.6.2 怎样看PHP的异常
      • 1.6.3 PHP中的错误级别
      • 1.6.4 PHP中的错误处理机制
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档