1. 程式人生 > >php裏面用魔術方法和匿名函數閉包函數動態的給類裏面添加方法

php裏面用魔術方法和匿名函數閉包函數動態的給類裏面添加方法

ndt trait 被調用 動態 obj 閉包 .html call eth

1.認識 __set (在給不可訪問屬性賦值時,__set() 會被調用)

也就是說你再訪問一個類裏面沒有的屬性,會出發這個方法

class A{
    private  $aa = ‘11‘;
    public function __set($name, $value)
    {
        $this->$name = $value;
    }
}
$a = new A();
$a->name = ‘name‘;
echo $a->name;

2.認識 __set (在對象中調用一個不可訪問方法時,__call() 會被調用。)

class B{
    private $bb = ‘22‘;
  public function __call($name, $arguments) { echo $name; var_dump($arguments); } } $b = new B(); $b->names();

3.動態添加方法

class B{
    private $bb = ‘22‘;
    public function __set($name, $value)
    {
        $this->$name
= $value; } public function __call($name, $arguments) {//註意:沒用形參$name return call_user_func($this->$name,$arguments);//通過這個把屬性的匿名方法加進來 註意:$arguments 是一個數組 } } $b = new B(); $b->names = function(){echo ‘this is a fun ‘;}; $b->names(); //這時候B類裏面已經有一個 屬性name 指向一個匿名方法 //怎麽運行呢? $b->name() 錯誤因為類裏面沒有這個方法 ---這個錯誤可以觸發__call()魔術方法 //這時候還不能在 匿名函數 中用B類裏面的 屬性

4.動態加方法之,讓閉包函數也能操作類裏面的屬性 參考(http://php.net/manual/zh/closure.bindto.php)

class C{
    private $cc = ‘33‘;
    public function __set($name, $value)
    {
        //$this->$name = $value; //(和上面例子比較  就改動了這個)
        $this->$name = $value->bindTo($this,$this);//復制當前閉包函數,綁定指定的$this作用域對象,這樣匿名函數就可以訪問類的屬性值了
    }
    public function __call($name, $arguments)
    {
        return call_user_func($this->$name,$arguments);
    }
}
$c = new C();
$c->username = function ($strs){
    var_dump($strs);//這裏其實是 call_user_func的$arguments傳過來的是數組
    $this->cc=4;//可以操作作用於的屬性值
    return ‘111‘;
};
echo $c->username(‘字符串‘);

一個完整的例子:

/**
 * 給類動態添加新方法
 *
 * @author fantasy
 */
trait DynamicTrait {
    /**
     * 自動調用類中存在的方法
     */
    public function __call($name, $args) {
        if(is_callable($this->$name)){
            return call_user_func($this->$name, $args);
        }else{
            throw new \RuntimeException("Method {$name} does not exist");
        }
    }
    /**
     * 添加方法
     */
    public function __set($name, $value) {
        $this->$name = is_callable($value)?
            $value->bindTo($this, $this):
            $value;
    }
}
/**
 * 只帶屬性不帶方法動物類
 *
 * @author fantasy
 */
class Animal {
    use DynamicTrait;
    private $dog = ‘汪汪隊‘;
}
$animal = new Animal;
// 往動物類實例中添加一個方法獲取實例的私有屬性$dog
$animal->getdog = function() {
    return $this->dog;
};
echo $animal->getdog();//輸出 汪汪隊

動態給類裏面加方法,就是把一個閉包函數通過__set和__call結合call_user_func()等方法,加入進去,

為了讓匿名函數或閉包函數可以訪問類的屬性值,需要結合Closure類的Closure::bindTo (復制當前包對象,綁定到指定this作用域)

參考:http://www.cnblogs.com/fps2tao/p/8727248.html

php裏面用魔術方法和匿名函數閉包函數動態的給類裏面添加方法