文档章节

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

lilugirl
 lilugirl
发布于 2013/06/08 14:29
字数 3089
阅读 258
收藏 2

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

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

{函数式编程  如LISP ,

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

}

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

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


1.1.1对象的“形”

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 对象的“本”

#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 对象与数组

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

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

1.1.4 对象与类

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方法

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方法

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);


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 对象。

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 类的组合与继承

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既可以使单继承模式的语言获得剁成继承的灵活,有可以避免多重继承带来的种种问题。

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 各种语言中的多态

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

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

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());


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 接口的作用

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

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

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接口的思考

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

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;


$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函数,返回对象属性的关联数组以及更多的信息

//返回对象属性的关联数组
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);


//反射获取类的原型
$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实现插件功能,做动态代理。

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里,遇到任何自身错误都会触发一个错误,而不是抛出异常(对于一些情况,会同时抛出异常和错误)。
$a=null;
try{
$a=5/0;
echo $a,PHP_EOL;
}catch(exception $e){
  $e->getMessage();
  $a=-1;
}
echo $a;



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

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 '注册成功';

}
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
$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中的错误处理机制

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接管,进而主动抛出异常,来捕获异常和非致命的错误。

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();
}


错误抛出

$divisor=0;
if($divisor==0){
 trigger_error("Can not  divide by zero",E_USER_ERROR);
}
echo 'break';




© 著作权归作者所有

共有 人打赏支持
lilugirl
粉丝 92
博文 378
码字总数 105471
作品 0
杨浦
程序员
整理了一些免费的编程中文书籍

在 github 上整理了一些免费的编程中文书籍 https://github.com/justjavac/free-programming-books-zh_CN 如果谁还有别的书籍,可在此留言。 语言无关类 WEB服务器 Nginx开发从入门到精通 (源...

justjavac
2013/11/04
882
2
《编写可读代码的艺术》读书笔记

最近常常来这个网站看看源码,看看博客,觉得只是从中获益,却没有做出自己的一些贡献,最近正好在读《The Art of Readable Code》这本书,就顺便把自己的读书笔记分享一下,大家多多批评指正...

爱编程的花栗鼠
2012/11/08
0
0
开源电子书

目录 语言无关类 操作系统 智能系统 分布式系统 编译原理 函数式概念 计算机图形学 WEB服务器 版本控制 编辑器 NoSQL PostgreSQL MySQL 管理和监控 项目相关 设计模式 Web 大数据 编程艺术 ...

zting科技
2017/12/11
0
0
java 7 入门书籍

一、Java从入门到精通 《Java从入门到精通(第3版)》从初学者角度出发,通过通俗易懂的语言、丰富多彩的实例,详细介绍了使用Java语言进行程序开发需要掌握的知识。 《Java从入门到精通(第3版...

modernizr
2014/05/15
6.2K
9
免费的编程中文书籍索引

免费的编程中文书籍索引,欢迎投稿。 国外程序员在 stackoverflow 推荐的程序员必读书籍,中文版。 stackoverflow 上的程序员应该阅读的非编程类书籍有哪些? 中文版 github 上的一个流行的编...

modernizr
2014/04/08
6.9K
24

没有更多内容

加载失败,请刷新页面

加载更多

阿里开源的 java 诊断工具—— Arthas

Arthas 是 阿里巴巴最近开源出来的一个针对 java 的工具,主要是针对 java 的问题进行诊断! 一、概述 这个工具可以协助你做下面这些事情: 这个类是从哪个 jar 包加载而来的? 为什么会报各...

xiaomin0322
18分钟前
1
0
去除shell read 读取的最后一个字符

# 读取管道数据cat | while read line; do echo $line # 此时 line包含 \n or \r\ndone# 去除 read 读取的特殊字符line=${line%?} # 去除最后一个字符...

tigerBin
18分钟前
1
0
Qt之listView设置编辑状态

QListView默认是可以编辑的,可以用setEditTrigers设置QListView的条目是否可以编辑,以及如何进入编辑状态。比如: ui->listView->setEditTriggers(QAbstractItemView::DoubleClicked | QAb...

OceanStar
19分钟前
1
0
Linux批量替换

sed -i "s/http://cache.co188.com///image.co188.com/g" grep http:\/\/image.co188.com -rl . *.html sed -i "s/http://cache.co188.com///cache.co188.com/g" grep http:\/\/cache.co188.......

cpaku
29分钟前
1
0
设置plsql永久注册码

填写注册码: Product Code:4t46t6vydkvsxekkvf3fjnpzy5wbuhphqz serial Number:601769 password:xs374ca...

小橙子的曼曼
33分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部