标签:多态

浏览模式: 标准 | 列表 | 图文
两年前写的php之call_user_func_array的简易用法

两年前写的php之call_user_func_array的简易用法

几年前写的东西了,翻出来重贴一下,呵呵


今天在群里面,有个叫lewis的在问call_user_func_array的用法,因为之前一直没有用过,也不能说什么,于是看一下手册,发现是这么写的:

call_user_func_array

(PHP 4 >= 4.0.4, PHP 5)

call_user_func_array -- Call a user function given with an array of parameters

Description

mixed call_user_func_array ( callback function, array param_arr )

Call a user defined function given by function, with the parameters in param_arr.
然后还有一个例子:

<?php
function debug($var, $val)
{
echo "***DEBUGGING\nVARIABLE: $var\nVALUE:";
if (is_array($val) || is_object($val) || is_resource($val)) {
print_r($val);
} else {
echo "\n$val\n";
}
echo "***\n";
}

$c = mysql_connect();
$host = $_SERVER["SERVER_NAME"];

call_user_func_array('debug', array("host", $host));
call_user_func_array('debug', array("c", $c));
call_user_func_array('debug', array("_POST", $_POST));
?>
相信看了例子之后应该有点明白了吧?
我自己是这么理解这个函数的,如果说的不对,还望各位高手不要耻笑:
该函数真正的用法有点类似于函数重载,因为他的第一个参数是字符型的,也就是函数的名称,第二个参数是数组,我们可以当成该函数的各个参数,而事实上也就是这么用的,如果你看过我的前一篇文章:PHP的伪重载 ,或许你能够理解,正是因为这个函数的存在,我发现函数重载也可以这样运用:
<?php
/**
* 例子写完后,本来认为完事了,结果遇到有人问call_user_func_array(),看了一下手册
* 原来,我上面的那个test函数还可以精简成如下的例子,
*/
function otest1 ($a)
{
echo( '一个参数' );
}

function otest2 ( $a, $b)
{
echo( '二个参数' );
}

function otest3 ( $a ,$b,$c)
{
echo( '三个啦' );
}

function otest ()
{
$args = func_get_args();
$num = func_num_args();
call_user_func_array( 'otest'.$num, $args );
}

otest(1,2);
看到不?而我最初的写法,在PHP的伪重载一文中有所提及,仅作参考。。。。

这些只是call_user_func_array的简易用法,在PHP4下测试过,而手册中还有一些将第一个参数当成数组来传入的例子,我在PHP4下是没有办法运行的,也许PHP5可以吧,但我不用PHP5的,也没有办法解释什么。谢谢各位
以前一直用PHP4的,现在用PHP5了,关于这个函数,大家可以看看thinkphp的functions.php中的getInstance方法,也是一个很好的诠释哦。
PHP 5.0 中多态性的实现方案浅析

PHP 5.0 中多态性的实现方案浅析

  一、 PHP 5和多态性

本文想讨论面向对象编程中最为重要的部分之一--多态 性的设计。为了说明问题,我使用了PHP 5。在你继续阅读之前,请首先明确本文并不是完全有关于PHP的。尽管这种语言在以前的两个主要版本中在快速开发方面已经取得很大的进步,但是,在其与更 为成熟的语言如C++或者Java相匹敌之前,它对于对象的支持还要经历一段历程。

如果你是一位面向对象编程的入门者,那么本文可能不适合你,因为多态性这部分知识比较特别:一旦理解了它,你将永远不会忘记。如果你想简单了解一点对象编程和设计知识,并且当某人说"某个对象是多态的"时,还不十分清楚这是什么意思的话,那么本文正适合你。
到本文最后,你应该知道什么是多态性以及如何把它应用到面向对象的设计中,并且你会了解PHP 5中对象编程的优点与不足。

二、什么是多态性?

多态性,其来自于dictionary.com的定义是"以不同形式,阶段或者类型出现在独立的组织中或者同种组织中,而不存在根本区别。"由该定义, 我们可以认为,多态性是一种通过多种状态或阶段来描述相同对象的编程方式。其实,它的真正意义在于:实际开发中,我们只需要关注一个接口或基类的编程,而 不必担心一个对象所属于的具体类(class)。

如果你熟悉设计模式,即使只是有个初步了解,那么你也会了解这个概念。事实上,多态 性可能是基于模式设计编程中的最伟大的工具。它允许我们以一种逻辑的方式来组织相类似的对象从而实现在具体编码时不必担心对象的具体类型;而且,我们只需 要对一个所期望的接口或基类编程即可。一个应用程序越抽象,则它就显得越灵活--而多态性是对行为加以抽象的最好的方式之一。

例如, 让我们考虑一个叫Person的类。我们可以用称为David,Charles和Alejandro的类来子类化Person。Person有一个抽象方 法AcceptFeedback(),所有的子类都要实现这个方法。这意味着,任何使用基类Person的子类的代码都能调用方法 AcceptFeedback()。你不必检查该对象是一个David还是一个Alejandro,仅知道它是一个Person就够了。结果是,你的代码 只需关注"最小公分母"-Person类即可。

在这个示例中的Person类也可以被创建为一个接口。当然,与上面相比存在一些区 别,主要在于:一个接口并没有给出任何行为,而仅确定了一组规则。一个Person接口要求的是"你必须支持AddFeedback()方法",而一个 Person类可以提供一些AddFeedback()方法的缺省代码-你对之的理解可以是"如果你不选择支持AddFeedback(),那么你应该提 供一种缺省实现。"至于如何选择接口或基类则并非本文的主题;但是,一般说来,你需要通过基类来实现一个缺省的方法。如果你能够简单地勾勒出你的类所要实 现的一组期望的功能,那么你也可以使用一个接口。

三、应用多态性设计

我们将继续使用Person基类的例子,现在让我们分析一个非多态性的实现。下列示例中使用了不同类型的Person对象--这是一种非常不理想的编程方式。注意,实际的Person类被省略。目前为止,我们仅关心代码调用的问题。

<?php
$name = $_SESSION['name'];
$myPerson = Person::GetPerson($name);
switch (get_class($myPerson)){
case 'David' :
$myPerson->AddFeedback('Great Article!','Some Reader', date('Y-m-d'));
break;
case 'Charles':
$myPerson->feedback[] = array('Some Reader', 'Great Editing!');
break;
case 'Alejandro' :
$myPerson->Feedback->Append('Awesome Javascript!');
break;
default :
$myPerson->AddFeedback('Yay!');
}
?>
  这个示例展示了行为不同的对象,还有一个switch语句用于区分不同的Person类对象,从而执行其各自相应的正确操作。注意,这里针对不同条件的回馈注释是不同的。在实际应用程序开发中可能不会出现这种情形;我仅为了简单地说明类实现中存在的区别。

下面的一个示例使用了多态性。
<?php
$name = $_SESSION['name'];
$myPerson = Person::GetPerson($name);
$myPerson->AddFeedback('Great Article!', 'SomeReader', date('Y-m-d'));
?>
  注意,这里没有switch语句,而最重要的是,缺乏有关Person::GetPerson()会返回什么类型的 对象。而另一个Person::AddFeedback()是一个多态方法。行为完全是由具体类进行封装的。请记住,在此无论我们使用的是 David,Charles还是Alejandro,调用代码从不必了解具体类的功能,而仅知道基类就可以了。

尽管我的示例并不完 美,但是,从调用代码的角度,它已经展示了多态性的基本用法。现在我们需要分析这些类的内部实现。从一个基类进行派生的一个最伟大的地方在于,该派生类能 够存取父类的行为,这种情况常常是缺省的实现,但是也可能出现在类继承链中用于创建更为复杂的行为。下面是这种情况的一个简单展示。
<?php
class Person{
function AddFeedback($comment, $sender, $date){
//把回馈添加到DB
}
}
class David extends Person{
function AddFeedback($comment, $sender){
parent::AddFeedback($comment, $sender,
date('Y-m-d'));
}
}
?>
  在此,David类中的AddFeedback方法实现中首先调用了Person::AddFeedback方法。你可能注意到,它模仿了C++,Java或C#中的方法重载。请记住,这仅是一个简单化的示例,并且你编写的实际代码完全依赖于你的实际工程。
四、PHP 5中的迟绑定

依我的看法,迟绑定正是使得Java和C#如此引人注目的重要原因。它们允许基类方法用"this"或$this来调用方法(即使它们不存在于基类中或调用一个基类中的方法,它有可能为继承类中的另一个版本所代替)。你可以认为如下的实现在PHP中是允许的:
<?php
class Person{
function AddFeedback($messageArray) {
$this->ParseFeedback($messageArray);
//写向数据库
}
}
class David extends Person{
function ParseFeedback($messageArray){
// 进行一些分析
}
}
?>
  记住,在Person类中并没有ParseFeedback。现在,假定你拥有这一部分实现代码(为了本例说明问题起见),那么这会导致$myPerson成为一个David对象:
<?php
$myPerson = Person::GetPerson($name);
$myPerson->AddFeedback($messageArray);
?>
  出现分析错误!大致错误信息为,方法ParseFeedback并不存在或者一些类似的信息。关于PHP 5中的迟绑定我们就讨论这些!下面我们再归纳一下迟绑定的概念。

迟绑定意味着,方法调用在最后时刻才绑定到目标对象。这意味着,当该方法被运行时刻调用时,那些对象已经有了一种具体类型。在我们上面的示例中,你调用 了David::AddFeedback(),而既然David::AddFeedback()中的$this引用一个David对象,那么你可以逻辑地 假定ParseFeedback()方法是存在的--但事实上它并不存在,因为AddFeedback()是在Person中定义的,并且从Person 类中调用ParseFeedback()。
不幸的是,没有简单的方法来消除PHP 5中的这种行为。这意味着,当你想创建一个灵活的多态类层次时你可能有点无能为力。

我必须指出,我选择PHP 5作为本文的表达语言仅仅是因为:这种语言并没有实现对象概念的完美抽象!因为PHP 5还处于其测试版本运行期,所以这是可以谅解的。另外,既然该语言中加入了抽象类和接口,迟绑定也应该被实现。

五、小结

至此,你应该基本了解什么是多态性以及为什么PHP 5在实现多态性方面并不完美。一般说来,你应该知道如何用一个多态性对象模型来封装有条件的行为。当然,这样会提高你的对象的灵活性,并且意味着更少的代 码实现。另外,通过封装满足一定条件的行为(具体要依赖于对象的状态),你还提高了代码的清晰程度。

-------------------------------------
注:现在大多数的程序都已经采用了这种特性,在框架中运用的犹为明显,虽然文章有点老了,但还是值得一看。
象最后一句说的,这提高了代码的清晰程度