php7魔术方法__call的最佳实战
浏览量:176
实战1:__call()实现php对象的链式操作
问题描述:
strlen(trim($str)),如果要实现类似js中的链式操作,
比如像下面这样应该怎么实现?
$str->trim()->strlen()
call_user_func详解
call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] ) : mixed
call_user_func 函数类似于一种特别的调用函数的方法,
第一个参数callback是被调用的回调函数,其余参数是回调函数的参数
使用方法如下:
function sum($a,$b){
return $a + $b;
}
//第一个参数sum是调用的方法名
//第2个参数7和第三个参数8是sum方法调用的参数
$result = call_user_func('sum',7,8);
echo $result;//输出结果15
如何通过类的魔术方法__call实现$str->trim()->strlen()的链式操作呢?
实现思路:
首先定义一个字符串类StringHelper,构造函数直接赋值value,然后链式调用trim()和strlen()函数,通过在调用的魔法函数__call()中使用
代码实现如下:
class StringHelper{
public $value;
public function __construct($str)
{
$this->value = $str;
}
public function __call($name, $arguments)
{
$this->value = call_user_func($name,$this->value);
return $this;
}
}
$str = new StringHelper(' hello ');
$result = $str->trim()->strlen();
//1.$str->trim(),由于StringHelper类没有trim方法,这时候调用_call魔术方法
//2.__call($name, $arguments)中$name的值是trim
//3.call_user_func的第一个参数值为调用的方法名trim,第二个参数就是$this->value
//$str->strlen()执行流程同$str->trim()
echo $result->value;
运行结果
5
实战2:利用__call进行PDO类的驱动设计
PDO结构图如下:
第一步:实现数据库实现类Mysql,Oracle,和Sqlite
代码如下:
class Mysql{
public function select($sql){
return 'Mysql'.$sql;//模拟数据库查询
}
}
class Oracle{
public function select($sql){
return 'Oracle'.$sql;//模拟数据库查询
}
}
class Sqlite{
public function select($sql){
return 'Sqlite'.$sql;//模拟数据库查询
}
}
第二步:实现数据库的驱动类
$驱动类->select();
驱动类并没有 select 方法,所以触发驱动类 __call() 调用,然后在__call方法实现对应类调用->select()
驱动类代码实现:
class DbDriver{
private $dbClassName;//数据库类名
public function __construct($dbClassName)
{
//保存数据库类名
$this->dbClassName = $dbClassName;
}
/**
* $驱动类->select($sql),驱动类DbDriver没有select方法,调用__call方法
* @param $name
* @param $arguments
*/
public function __call($name, $arguments)
{
$dbClassName = $this->dbClassName;//类名
$dbClassObj = new $dbClassName ();//创建类对象
$functionName = $name;
//暂不考虑数据类不存在的方法判断
// if(!method_exists($dbClass,$functionName)){
// return false;//未定义该方法
// }
return $dbClassObj->$functionName($arguments[0]);//目前select方法只有一个参数
}
}
PDO代码运行实例:
$dbDriver = new DbDriver('Mysql');
$result = $dbDriver->select('');
echo $result;//输出mysql
$dbDriver = new DbDriver('Oracle');
$result2 = $dbDriver->select('');
echo $result2;//输出Oracle
$dbDriver = new DbDriver('Sqlite');
$result3 = $dbDriver->select('');
echo $result3;//输出Sqlite
如果日后更换了数据驱动,只需将$dbDriver = new DbDriver('Mysql');
换成$dbDriver = new DbDriver('Sqlite'); 就可以了,代码无需做其他改动。
完整实例代码:
//数据类实现
class Mysql{
public function select($sql){
return 'Mysql'.$sql;//模拟数据库查询
}
}
class Oracle{
public function select($sql){
return 'Oracle'.$sql;//模拟数据库查询
}
}
class Sqlite{
public function select($sql){
return 'Sqlite'.$sql;//模拟数据库查询
}
}
//PDO驱动类实现
class DbDriver{
private $dbClassName;//数据库类名
public function __construct($dbClassName)
{
//保存数据库类名
$this->dbClassName = $dbClassName;
}
/**
* $驱动类->select($sql),驱动类DbDriver没有select方法,调用__call方法
* @param $name
* @param $arguments
*/
public function __call($name, $arguments)
{
$dbClassName = $this->dbClassName;//类名
$dbClassObj = new $dbClassName ();//创建类对象
$functionName = $name;
//暂不考虑数据类不存在的方法判断
// if(!method_exists($dbClass,$functionName)){
// return false;//未定义该方法
// }
return $dbClassObj->$functionName($arguments[0]);//目前select方法只有一个参数
}
}
//驱动类调用Mysql类
$dbDriver = new DbDriver('Mysql');
$result = $dbDriver->select('');
echo $result;//输出mysql
//驱动类调用Oracle类
$dbDriver = new DbDriver('Oracle');
$result2 = $dbDriver->select('');
echo $result2;//输出Oracle
//驱动类调用Sqlite类
$dbDriver = new DbDriver('Sqlite');
$result3 = $dbDriver->select('');
echo $result3;//输出Sqlite


感谢支持与鼓励~