PHP: 在类(class)中加载动态函数, 变量函数或半变量函数 variable function/method

最终实例在下方

以前用过cakephp, 他们的数据库查询还是蛮强大的, 后来好奇它的类的写法,比如:

<?php
$this->Post->findByTitle('My First Blog Post');
$this->Author->findByLastName('Rogers');
  • findBy<fieldName>
  • string $value
  • findAllBy<fieldName>
  • string $value

findAllBy 或者 findBy 后面可以跟变量, 它大概的方法就是使用了三个核心内置函数: __call, method_exists() 和 call_user_func_array (或者call_user_func), 下面先讲解他们各自的含义和用法:

__call()

定义和用法

__call() 这个方法用来监视一个对象中的其它方法。如果你试着调用一个对象中不存在或被权限控制中的方法,__call 方法将会被自动调用。

注:通常被称为魔法函数。

语法: __call(name, arguments)

参数 描述
name 方法名
arguments 传递的参数

例子

<?php
class MyClass {
    public function __call($name, $arguments) {
        // 注意: $name 区分大小写
        echo "调用了方法: '$name'<br/> ";
        echo '参数是:'.implode(', ', $arguments). "\n";
    }
}
$obj = new MyClass;
$obj->callMe('abc','123');

//运行结果:
//调用了方法:callMe
//参数是:abc,123

method_exists()

定义和用法

检查类的方法是否存在于指定的 object中。

语法: method_exists(object,method_name)

参数 描述
object 规定的对象示例或者类名。
method_name 规定的方法名。

例子

<?php
class Test {
    public function explicit( ) {
        // ...
    }
    public function __call( $meth, $args ) {
        // 魔术方法,当调用的方法不存在时自动调用此方法
    }
}
 
$Tester = new Test();
// method_exists() -方法是否存在
var_export(method_exists($Tester, 'anything')); // false
// is_callable() - 检测参数是否可调用
var_export(is_callable(array($Tester, 'anything'))); // true
?>

call_user_func()

定义和用法

调用指定函数,并传入参数。

语法

  1. call_user_func(callback, parameter)
参数 描述
callback 调用的函数名称
parameter 传入的参数

例子

<?php
error_reporting(E_ALL);
function increment(&$var)
{
    $var++;
}
 
$a = 0;
call_user_func('increment', $a);
echo $a."\n";
 
call_user_func_array('increment', array(&$a)); // PHP 5.3前 版本可用
echo $a."\n";

//输出:
//0
//1

call_user_func_array()

定义和用法

用一个数组作为参数调用一个回调函数·返回值为回调函数执行的结果或者为false

语法

  1. call_user_func_array(callback , param_arr)
参数 描述
callback 要调用的回调函数,可以是函数或者类方法
param_arr 传入的参数

例子

<?php
function foobar($arg, $arg2) {
    echo __FUNCTION__, " got $arg and $arg2\n";
}
class foo {
    function bar($arg, $arg2) {
        echo __METHOD__, " got $arg and $arg2\n";
    }
}
 
// 调用 foobar() 函数并传入两个参数
call_user_func_array("foobar", array("one", "two"));
 
// 调用 $foo->bar() 方法并传入两个参数
$foo = new foo();
call_user_func_array(array($foo, "bar"), array("three", "four"));

//输出:
//foobar got one and two
//foo::bar got three and four

也可以参考:call_user_func和call_user_func_array的用法

官方有下面的实例:

<?php
class A
{
    function __construct()
    {
        $a = func_get_args();
        $i = func_num_args();
        if (method_exists($this,$f='__construct'.$i)) {
            call_user_func_array(array($this,$f),$a);
        }
    }
   
    function __construct1($a1)
    {
        echo('__construct with 1 param called: '.$a1.PHP_EOL);
    }
   
    function __construct2($a1,$a2)
    {
        echo('__construct with 2 params called: '.$a1.','.$a2.PHP_EOL);
    }
   
    function __construct3($a1,$a2,$a3)
    {
        echo('__construct with 3 params called: '.$a1.','.$a2.','.$a3.PHP_EOL);
    }
}
$o = new A('sheep');
$o = new A('sheep','cat');
$o = new A('sheep','cat','dog');

// results:
// __construct with 1 param called: sheep
// __construct with 2 params called: sheep,cat
// __construct with 3 params called: sheep,cat,dog
?>

主要的函数解释完了, 下面的就写一个简单的实例, 以实现上面cakephp中的findBy用法:

<?php

class post
{
    public function __call($name, $arguments)
    {
        if (method_exists($this,$name)) call_user_func_array(array($this,$name),$arguments);
        else
        {
            if(stripos(' '.$name,'findBy'))  call_user_func(array($this,'findBy'),array(str_ireplace('findBy','',$name)=>implode('',$arguments)));
            else echo 'error';
        }
    }

    function findAll($data)
    {
        echo 'All Here: '.(is_array($data) ? implode(',',$data) : $data).'<br>';
    }

    function findBy($data)
    {
        echo '<pre>'; print_r($data); echo '</pre>';
    }
}

$post = new post;
$post->findAll('justcode.ikeepstudying.com');
$post->findAll(array('justcode','ikeepstudying','com'));
$post->findByTitle('justcode.ikeepstudying.com');

效果如下:

Selection_119

更多参考:

php框架–php框架的连贯查询实现原理

PHP: 关键字global 和 超全局变量$GLOBALS的用法、解释、区别

PHP: 手把手编写自己的 MVC 框架实例教程

JavaScript使用PHP函数 PHP extensions in JavaScript

 

原文: PHP: 在类(class)中加载动态函数, 变量函数或半变量函数 variable function/method

One Comment

Leave a Reply