面向对象程序设计是一种程序设计范型,同时也是一种程序开发方法。它将对象做为程序的基本单元,将程序和数据封装其中,以提升软件的重用性,灵活性和可扩展性。 php
{函数式编程 如LISP , mysql
命令式编程 { 面向过程, 面向对象} sql
} 数据库
类是对象的抽象组织,对象是类的具体存在。 编程
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();
所谓序列化,就是把保存在内存中的各类对象状态(属性)保存起来,而且在须要时能够还原出来。 数组
对象序列化后,存储的只是只是对象的属性。
对象就是数据,对象自己不包含方法。可是对象有一个“指针”指向一个类,这个类里能够有方法。 dom
序列化和反序列化时都须要包含类的对象的定义,不然可能返回不正确的结果。 ide
#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;
对象是一种很普通的变量,不一样的是其携带了对象的属性和类的入口。 函数
$student_arr=array('name'=>'Tom','gender'=>'male'); echo "\n"; echo serialize($student_arr);
对象和数组的区别在于:对象还有个指针,指向了它所属的类。 this
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);
当一个对象的实例变量应用其余对象时,序列化该对象时也会对引用对象进行序列化。
语法糖:指那些没有给计算机语言添加新功能,而只是对人类来讲更“甜蜜”的语法。 如魔术方法的写法。
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;
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;
只有实现了__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);
继承是类级别的复用,多态是方法级别的复用。
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();
重载不是面向对象里的东西,它数据域多态的一种表现形式。
多态性是一种经过多种状态或者阶段描述相同对象的编程方式。实际开发中,只要关心一个接口或者基类的编程,而没必要关心一个对象所属于的具体类。
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);
接口中全部的方法都是抽象的,没有程序体。
接口的方法必须被所有实现,不然将报错。
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());
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中的接口没有契约限制,缺乏足够多的内部接口。
反射是指在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类,方法,属性等详细信息,包括注释。
这种动态获取信息以及动态调用对象方法的功能成为反射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";
反射能够用于文档生成,作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');
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 语言级别的健壮性要求
能够把异常形成的逻辑中断破坏下降到最小范围内,并通过补救处理后不影响业务逻辑的完整性;乱抛异常和只抛不捕获,或捕获而不补救,会致使数据混乱。
$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 '致命错误后呢,还会执行吗?'
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';