如何防止調用不存在的方法而出錯,使用__call魔術重載方法.
__call方法原型如下:
mixed __call(string $name,array $arguments)
當調用一個不可訪問的方法(如未定義,或者不可見時), __call()就會被調用.其中$name參數是要調用的方法名稱.$arguments參數是一個數組,包含者要傳遞給方法的參數,
如下所示:
<?php
class HandsonBoy
{
private $name = 'chenqionghe';
private $age = 18;
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 HandsonBoy();
$a->make(5);
$a->make(5,6);
以上代碼模擬了類似其他語言中的根據參數類型進行重載.跟__call配套的魔方方法是__callStatic.
當然,使用魔術方法"防止調用不存在的方法面報錯",並不是魔術方法的本質.實際上,魔術方法使用方法的動態創建變為可能.這在MVC等框架設計中是很有用的語法.假設一個控制器調用了不存在的方法,那么只要定義了__call魔術方法,就能很友好地處理這種情況.
以下代碼通過使用_callStatic這一魔術方法進行方法的動態創建和延遲綁定,實現一個簡單的ORM模型
<?php
abstract class ActiveRecord
{
protected static $table;
protected $fieldvalue;
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)
{
$class = get_called_class();//獲取靜態方法調用的類名
$domain = new $class();
$domain->fieldvalues = array();
$domain->select = $query;
foreach ($class::$fields as $field => $type)
{
$domain->fieldvalues[$field] = 'TODO:set from sql result by ' . $field;
}
return $domain;
}
}
class Customer extends ActiveRecord
{
protected static $table = 'custdb';
protected static $fields = array(
'id' => 'int',
'email' => 'int',
'lastname' => 'varchar'
);
}
class Sales extends ActiveRecord
{
protected static $table = 'salesdb';
protected static $fields = array(
'id' => 'int',
'item' => 'varchar',
'qty' => 'int'
);
}
var_dump(Customer::findById(123)->select);
var_dump(Customer::findById(123)->email);
var_dump(Sales::findByLastname('Denoncourt')->select);
