(本分类文章源代码原型来源<<深入PHP面向对象,模式与实践>>)
一 PHP类和对象的高级特性
1 在类中使用self(),表示对类本身的引用(解析时的上下文),比如下面例子使用self()会报错,无法实例化DomainObject
2 在类中使用static(),作用和self()差不多,区别在于staitc()返回的是调用时的上下文
abstract class DomainObject {
private $group;
public function __construct(){
$this->group=static::getGroup();
}
public static function create(){
return new static();
}
public static function getGroup(){
return 'Default';
}
}
class User extends DomainObject{
}
class Document extends DomainObject{
public static function getGroup(){
return 'Document';
}
}
print_r(Document::create()); //Document Object ( [group:DomainObject:private] => Document )
3 异常是需要手动抛出的,区别于JAVA等语言
class Conf{
private $file;
private $xml;
private $lastMatch;
function __construct($file){
$this->file=$file;
if(!file_exists($file)){
throw new Exception("File dose not exits");
}
$this->xml=simplexml_load_file($file);
}
public function write(){
file_put_contents($this->file, $this->xml->asXml());
}
public function get($str){
$matches=$this->xml->xpath("/conf/item[@name=\"$str\"]");
if(count($matches)){
$this->lastMatch=$matches[0];
return (string)$matches[0];
}
return null;
}
public function set($key,$value){
if(! is_null($this->get($key)) ){
$this->lastMatch[0]=$value;
return;
}
$this->xml->addChild('item',$value)->addAttribute('name',$key);
}
}
try{
$conf=new Conf("./src/MyXml.xml_");
}catch(Exception $e){
die($e->__toString());
}
print_r($conf->get("Tom"));
$conf->set("Tom", "A Cat");
print_r($conf);
4 拦截器(interceptor)
__get(),__set(),__isset(),__unset(),__call()
//下面展示一下__call()拦截器
class PersonWriter{
function writeName(Person $p){
print $p->getName()."\n";
}
function writeAge(Person $p){
print $p->getAge()."\n";
}
}
class Person{
private $writer;
private $id=5;
function __construct(PersonWriter $writer){
$this->writer=$writer;
}
//检查$writer是否包含相关方法,如果有则委托它来处理(注意weiter所有方法都需要Person对象)
function __call($methodName,$args){
if(method_exists($this->writer, $methodName)){
return $this->writer->$methodName($this);
}
}
// function __clone(){
// $this->id=0;
// }
function getName(){
return 'Bob';
}
function getAge(){
return '44';
}
}
$person = new Person(new PersonWriter());
$person->writeName();//Output==>Bob
5 类中定义常量,获取方法 类名::常量名(不需要美元符号)
6 使用clone关键字可以复制一个对象,如果在被赋值的对象所属的类中添加__clone()方法,则在被clone时会自动调用(可以用来处理一些被clone对象的属性,比如改变其中一个值,或者深度拷贝其中某个属性(本身也是对象))
7 手动创建具备回调功能的类(在开发框架中非常有用.)
class Product{
public $name;
public $price;
function __construct($n,$p){
$this->name=$n;
$this->price=$p;
}
}
class ProcessSale{
private $callbacks;
function registerCallback($callback){
if(!is_callable($callback)){
throw new Exception("$callback not callable");
}
$this->callbacks[]=$callback;
}
function sale($product){
print "{$product->name}:processing \n";
foreach($this->callbacks as $callback){
call_user_func($callback,$product);
}
}
}
class Mailer{
function doMail(Product $p){
print " mailing ({$p->name})\n";
}
}
$product=new Product('peanut', 100);
$processSale=new ProcessSale();
$logger=function(Product $p){
print " logging {$p->name} \n";
};
//在不改动processSale类的情况下,为sale方法增加了记录功能(在框架开发中非常有用)
$processSale->registerCallback($logger);
//也可以通过数组(对象,方法)这样传入回调函数
$processSale->registerCallback(array(new Mailer(),"doMail"));
$processSale->sale($product);
8 PHP中的闭包(代码大部分和第7点相同)
class Product{
public $name;
public $price;
function __construct($n,$p){
$this->name=$n;
$this->price=$p;
}
}
class ProcessSale{
private $callbacks;
function registerCallback($callback){
if(!is_callable($callback)){
throw new Exception("$callback not callable");
}
$this->callbacks[]=$callback;
}
function sale($product){
print "{$product->name}:processing \n";
foreach($this->callbacks as $callback){
call_user_func($callback,$product);
}
}
}
class Mailer{
function doMail(Product $p){
print " mailing ({$p->name})\n";
}
}
//一个闭包的例子,使用use关键字,跟JS不同的是,如果不使用use的话,参数amt,count将变成未识别的
class Totalizer{
static function warnAmount($amt){
$count=0;
return function(Product $p) use ($amt,&$count){
$count+=$p->price;
print " count:$count\n";
if($count>$amt){
print " high price reached:{$count}\n";
}
};
}
}
$processSale=new ProcessSale();
$logger=function(Product $p){
print " logging {$p->name} \n";
};
//在不改动processSale类的情况下,为sale方法增加了记录功能(在框架开发中非常有用)
$processSale->registerCallback($logger);
//也可以通过数组(对象,方法)这样传入回调函数
$processSale->registerCallback(array(new Mailer(),"doMail"));
$processSale->registerCallback(Totalizer::warnAmount(12));
$processSale->sale(new Product('peanut', 12));
$processSale->sale(new Product('potato', 6));