PHP核心技术——魔术方法

魔术方法:

  • 魔术方法是以两个下画线开头、具有特殊作用的一些方法,可以看做PHP的“语法糖”。

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 "not default";
            $this->$name="setting default";
        }
        return $this->$name;
    }
}

$a=new Account();
echo $a->user;
echo "-----------\n";
$a->name=5;
echo $a->name;
echo "-----------\n";
echo $a->big;
  • 而PHP则在一个类中只允许有一个构造函数
  • PHP提供的“重载”指动态地“创建”类属性和方法。因此,set和get方法被归到重载里。

call和callStatic方法:

  • 当调用一个不可访问的方法(如未定义,或者不可见)时,call()会被调用。其中name参数是要调用的方法名称。arguments参数是一个数组,包含着要传递给方法的参数
  class callFun
  {

      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 'wrong',PHP_EOL;
                  break;
          }
      }
  }
  $a =new callFun;
  $a->make(5);
  $a->make(5,6);

  • 这段代码通过使用callStatic这一魔术方法进行方法的动态创建和延迟绑定,实现一个简单的ORM模型。
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]='TODO: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 Sales extends ActiveRecord{
    protected static $table='salesdb';
    protected static $fields=array(
    'id'=>'int',
    'item'=>'varchar',
    'qty'=>'int'
    );
}

assert("select * from custdb where id=123"==Customer::findById(123)->select);
assert("TODO:set from sql result"==Customer::findById(123)->email);
assert("select * from salesdb where id=321"==Sales::findById(321)->select);
assert("select * from custdb where Lastname='Denoncourt'"==Customer::findByLastname('Denoncourt')->select);

toString方法:

  • 当进行测试时,需要知道是否得出正确的数据。比如打印一个对象时,看看这个对象都有哪些属性,其值是什么,如果类定义了toString方法,就能在测试时,echo打印对象体,对象就会自动调用它所属类定义的toString方法,格式化输出这个对象所包含的数据。如果没有这个方法,那么echo一个对象将报错,例如“Catchable fatal error:Object of class Account could not be converted to string”语法错误,实际上这是一个类型匹配失败错误。不过仍然可以用print_r()和var_dump()函数输出一个对象。当然,toString是可以定制的,所提供的信息和样式更丰富。
class Account
{
    public $user=1;
    private $pwd=2;
    //自定义的格式化输出方法
    public function __toString()
    {
        return "{$this->user}, {$this->pwd}";
    }
}

$a = new Account();
echo $a;
echo PHP_EOL;
print_r($a);

参考资料

  • [PHP核心技术与最佳实践]
posted @ 2019-03-27 15:09  高级生命体  阅读(319)  评论(0编辑  收藏  举报