文档章节

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

lilugirl
 lilugirl
发布于 2013/06/08 14:29
字数 3089
阅读 257
收藏 2
点赞 0
评论 0

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

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

{函数式编程  如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
粉丝 91
博文 340
码字总数 102757
作品 0
杨浦
程序员
整理了一些免费的编程中文书籍

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

justjavac ⋅ 2013/11/04 ⋅ 2

推荐一些不错的计算机书籍

推荐一些不错的计算机书籍。 # PHP 《PHP程序设计》(第2版) --PHP语法和入门最好的书 《PHP5权威编程》 --PHP入门后升级书 《深入PHP:面向对象、模式与实践》(第3版) --理解PHP中的面向对象...

Junn ⋅ 2013/08/30 ⋅ 0

开源电子书

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

zting科技 ⋅ 2017/12/11 ⋅ 0

免费的编程中文书籍索引

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

modernizr ⋅ 2014/04/08 ⋅ 24

《编写可读代码的艺术》读书笔记

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

爱编程的花栗鼠 ⋅ 2012/11/08 ⋅ 0

java 7 入门书籍

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

modernizr ⋅ 2014/05/15 ⋅ 9

程序员练级-关键提炼

启蒙入门 1.学习一门脚本语言,例如Python/Ruby 2.熟悉Unix/Linux Shell和常见的命令行 3. 学习Web基础(HTML/CSS/JS) + 服务器端技术 (LINUX + APACHE + MYSQL + PHP)      未来必然是W...

zhayefei ⋅ 2013/01/23 ⋅ 4

一些经典的计算机书籍

以下列表中的计算机书籍(中文版)来自微博:@程序员的那些事 粉丝的推荐。按推荐次数,从高到低往下排。如果大家还有其他计算机相关的经典书籍推荐,请在评论中留言,或者在这条微博的评论中...

随影求是 ⋅ 2012/03/15 ⋅ 0

敏捷教练成长记:漫漫长路第三周

看到跆拳道的软文,讲到: 学跆拳道的正确顺序: 第一阶段:有兴趣 第二阶段:没兴趣 第三阶段:逼练习 第四阶段:成习惯 第五阶段:有兴趣 第六阶段:真热爱 大部分家长在孩子第二阶段时放弃...

转型实践者 ⋅ 2017/11/17 ⋅ 0

Fanta/free-programming-books-zh_CN

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

Fanta ⋅ 2016/11/14 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

如何优雅的编程——C语言界面的一点小建议

我们鼓励在编程时应有清晰的哲学思维,而不是给予硬性规则。我并不希望你们能认可所有的东西,因为它们只是观点,观点会随着时间的变化而变化。可是,如果不是直到现在把它们写在纸上,长久以...

柳猫 ⋅ 37分钟前 ⋅ 0

从零手写 IOC容器

概述 IOC (Inversion of Control) 控制反转。熟悉Spring的应该都知道。那么具体是怎么实现的呢?下面我们通过一个例子说明。 1. Component注解定义 package cn.com.qunar.annotation;impo...

轨迹_ ⋅ 37分钟前 ⋅ 0

系统健康检查利器-Spring Boot-Actuator

前言 实例由于出现故障、部署或自动缩放的情况,会进行持续启动、重新启动或停止操作。它可能导致它们暂时或永久不可用。为避免问题,您的负载均衡器应该从路由中跳过不健康的实例,因为它们...

harries ⋅ 38分钟前 ⋅ 0

手把手教你搭建vue-cli脚手架-详细步骤图文解析[vue入门]

写在前面: 使用 vue-cli 可以快速创建 vue 项目,vue-cli很好用,但是在最初搭建环境安装vue-cli及相关内容的时候,对一些人来说是很头疼的一件事情,本人在搭建vue-cli的项目环境的时候也是...

韦姣敏 ⋅ 49分钟前 ⋅ 0

12c rman中输入sql命令

12c之前版本,要在rman中执行sql语句,必须使用sql "alter system switch logfile"; 而在12c版本中,可以支持大量的sql语句了: 比如: C:\Users\zhengquan>rman target / 恢复管理器: Release 1...

tututu_jiang ⋅ 今天 ⋅ 0

Nginx的https配置记录以及http强制跳转到https的方法梳理

Nginx的https配置记录以及http强制跳转到https的方法梳理 一、Nginx安装(略) 安装的时候需要注意加上 --with-httpsslmodule,因为httpsslmodule不属于Nginx的基本模块。 Nginx安装方法: ...

Yomut ⋅ 今天 ⋅ 0

SpringCloud Feign 传递复杂参数对象需要注意的地方

1.传递复杂参数对象需要用Post,另外需要注意,Feign不支持使用GetMapping 和PostMapping @RequestMapping(value="user/save",method=RequestMethod.POST) 2.在传递的过程中,复杂对象使用...

@林文龙 ⋅ 今天 ⋅ 0

如何显示 word 左侧目录大纲

打开word说明文档,如下图,我们发现左侧根本就没有目录,给我们带来很大的阅读障碍 2 在word文档的头部菜单栏中,切换到”视图“选项卡 3 然后勾选“导航窗格”选项 4 我们会惊奇的发现左侧...

二营长意大利炮 ⋅ 今天 ⋅ 0

智能合约编程语言Solidity之线上开发工具

工具地址:https://ethereum.github.io/browser-solidity/ 实例实验: 1.创建hello.sol文件 2.调试输出结果

硅谷课堂 ⋅ 今天 ⋅ 0

ffmpeg 视频格式转换

转 Mp4 格式 #> ffmpeg -i input.avi -c:v libx264 output.mp4#> ffmpeg -i input.avi -c:v libx264 -strict -2 output.mp4#> ffmpeg -i input.avi -c:v libx264 -strict -2 -s 1......

Contac ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部