一. PHP模式设计----PHP类和对象的高级特性

(本分类文章源代码原型来源<<深入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));

















    原文作者:足境
    原文地址: https://blog.csdn.net/im_kk/article/details/40510363
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞