在框架开发,模块化开发等场合,我们可能有一种需求,那就是在PHP运行时动态实例化对象。
什么是动态实例化对象呢?我们先来看一下PHP有一种变量函数(可变函数)的概念,例如如下代码:
function foo() { echo 'This is the foo function'; } $bar = 'foo'; $bar();
运行上述代码将会输出“This is the foo function”。具体请参考PHP手册:可变函数。当然,如果需要动态调用的话,那么就使用call_user_func或call_user_func_array函数。这两个函数的用法不是本文的重点,不懂的同学请查阅其它资料。回到本文的话题上:什么是动态实例化对象?本人认为动态实例化对象,即是:需要实例化的对象是在程序运行时(run-time)动态决定(由变量决定)需要实例化什么样的对象,而不是直接写死在代码里。
通过上述例子我们已经知道了如何在运行时动态调用一个函数了,在现在面向对向如此流行的今天,在一些代码中,我们需要去动态去实例化一个类,该怎么做呢?
情况一:类的构造函数没有参数或参数的个数是确定的
如果类的构造函数没有参数或者我们要实例化的类根本没有构造函数,似乎简单一点,可以照上面的例子改一个嘛,嗯,照葫芦画瓢,谁不会:
代码示例:(构造函数没有参数)
class FOO { private $a, $b; public function construct() { $this->a = 1; $this->b = 2; } public function test() { echo 'This is the method test of class FOO<br />'; echo '$this->a=', $this->a, ', $this->b=', $this->b; } } $bar = 'FOO'; $foo = new $bar(); $foo->test();
运行一下,就看到了输出了如下结果:
This is the method test of class FOO $this->a=1, $this->b=2
嗯,我们要传参的话,那么就这样吧:
class FOO { private $a, $b; public function construct($a, $b) { $this->a = $a; $this->b = $b; } public function test() { echo 'This is the method test of class FOO<br />'; echo '$this->a=', $this->a, ', $this->b=', $this->b; } } $bar = 'FOO'; $foo = new $bar('test', 5); $foo->test();
一样可以得到类似的结果:
This is the method test of class FOO $this->a=test, $this->b=5
很理想嘛。
情况二:类的构造函数的参数个数不确定
这种情况就要麻烦很多了,但是如果要写得比较通用的话,就不得不考虑这种情况了。例如,我们有如下两个类
class FOO { public function test() { echo 'This is the method test of class FOO'; } } class BAR { private $a, $b; public function construct($a, $b) { $this->a = $a; $this->b = $b; } public function test() { echo 'This is the method test of class BAR<br />'; echo '$this->a=', $this->a, ', $this->b=', $this->b; } }
我们想要一个通用的方式来实例化这两个类。我们注意到FOO类是没有写构造函数的,或者是可以认为FOO类的构造函数的参数个数为零;而BAR类的构造函数却有参数。还好,PHP5已经足够强大了,引入了反射的概念,具体请参考PHP手册:反射,虽然手册上也没有什么可参考的:)。还好,命名写得不错,从类名和方法名上面已经可以看出大概的端倪,不需要太多的文字。
那么好吧,就让我们用PHP5的反射来着手这个事情:
(还在用PHP4的同学请不要走开,如果你拥有一个没有反射的PHP版本或者是你为了兼容也好还是不想升级也好,反正不想用反射的,下面有解决方案)
$class = new ReflectionClass('FOO'); $foo = $class->newInstance(); //或者是$foo = $class->newInstanceArgs(); $foo->test();
看到什么了没有?接着来:
$class = new ReflectionClass('BAR'); $bar = $class->newInstanceArgs(array(55, 65)); $bar->test();
OK,似乎可以了,那么就整理一下吧,来个通用函数,我们想这么设计,此函数的第一个函数是要实例化的类名,从第二个参数开始就是要实例化类的构造函数的参数,有几个就写几个上去,没有就不写。要想实现参数个数可变的函数,我们有两种方法:
第一种是类似于:
function foo($arg1, $arg2 = 123, $arg3 = 'test', $arg4 = null, ....... ) { //some code; }
的办法,这种方法有两个缺点,第一个是你如果需要传100个参数难道就写100个参数吗?第二个是你还要在程序里判断哪个参数是不是null,或是其它默认值。(题外话:这种写法的参数默认值必须放在最后,你不能将没有默认值的参数插在有默认值的中间或前面,否则你调用的时候也必须显式地写上有默认值参数的值)
另一种实现参数数量可变的方法是在函数里用PHP的内置函数func_get_args(猛击这里看手册)取得传给函数的参数。类似的函数有func_get_num和func_get_arg,算了,我懒,你们自己找手册看吧。
那么,用这个函数似乎要方便很多,我们根据想象的函数参数的排列,代码应该是这个样子的:
function newInstance() { $arguments = func_get_args(); $className = array_shift($arguments); $class = new ReflectionClass($className); return $class->newInstanceArgs($arguments); }
OK,让我们来看一下效果:
$foo = newInstance('FOO'); $foo->test(); //输出结果: //This is the method test of class FOO $bar = newInstance('BAR', 3, 5); $bar->test(); //输出结果: //This is the method test of class BAR //$this->a=3, $this->b=5
短短四行代码,效果相当完美啊。那么,如果应用到类里面,我们可以利用这种思想,直接写成魔术方法,可以让我们的类更酷哦!
class INSTANCE {
function call($className, $arguments) {
$class = new ReflectionClass($className);
return $class->newInstanceArgs($arguments);
}
}
$inst = new INSTANCE();
$foo = $inst->foo();
$foo->test();
//输出结果:
//This is the method test of class FOO
$bar = $inst->bar('arg1', 'arg2');
$bar->test();
//输出结果:
//This is the method test of class BAR
//$this->a=3, $this->b=5
咔咔,爽吧。
接下来讨论一下不使用反射类的情况。例如PHP4中就没有反射,而一些老项目就是运行在PHP4上面的。或者是要保证项目对未知环境的兼容性,Whatever,来关心一下怎么动态传参吧。PHP中动态传参的函数只有一个:call_user_func_array(轻击此处查看手册)。这是一个动态调用函数的函数,作用是可以将函数的参数以数组的形式传递给要调用的函数。好吧,我自己也被自己绕晕了,直接来看实例:
function foo($a, $b) { echo '$a=', $a, '<br />'; echo '$b=', $b; } call_user_func_array('foo', array(1, 'string')); //本例输出结果: //$a=1 //$b=string
那么,要实现用这种方法来动态实例化对象并传参,呃……,只有曲线救国了,我们得先写一个函数,让这个函数来实例化对象,而这个函数的参数就原原本本地传给要实例化对象的类的构造函数就好了。打住!那这个函数得有几个参数啊?怎么实现传递不同个数的参数呢?嘿嘿,我一声冷笑,你忘了PHP里提供一个创建匿名函数的函数吗?(又开始绕起来了……)create_function(手册在此),照着手册里面的例子直接画就可以了,我也懒得打字了,直接看下面的代码,注释我写清楚点大家都明白了:
function newInst() { //取得所有参数 $arguments = func_get_args(); //弹出第一个参数,这是类名,剩下的都是要传给实例化类的构造函数的参数了 $className = array_shift($arguments); //给所有的参数键值加个前缀 $keys = array_keys($arguments); array_walk($keys, create_function('&$value, $key, $prefix', '$value = $prefix . $value;'), '$arg_'); //动态构造实例化类的函数,主要是动态构造参数的个数 $paramStr = implode(', ',$keys); $newClass=create_function($paramStr, "return new {$className}({$paramStr});"); //实例化对象并返回 return call_user_func_array($newClass, $arguments); }
好了,至于效果是什么,就麻烦各位看官自己动动手,运行一下看看,是不是自己期望的结果。
如果改写成类里面的魔术方法,哼哼,威力嘛,你懂的!然后呢,我还是懒了,如果要写成魔术方法的话,相信这么easy的事情你很轻松就办到了。就当一个作业吧。另,本文的代码都是本人运行过的,但是,写文章的时候没有使用复制/粘贴功能,所以,你最好是也不要复制粘贴。如果从本文中的代码copy下来运行出错的话,还烦请各位自己debug一下,编程不就是要自己写么。
本来这个话题到这里就应该可以结束了,但是想到我在想到这个办法之前用的方法(好绕……),本着重在交流的态度,一起放出来。我例两个关键函数吧:extract和eval。只是我个人觉得用eval函数比较山寨,能不用最好不用。于是又想出了上面的办法,哈哈,编程最重要的是思想,不是吗?好,又是一道作业题了,大家可以试试用这两个函数(当然也会用到别的函数)来实现带不定数量的参数动态实例化对象的函数。
以上是php动态实例化对象并向构造函数传递参数的案例分析的详细内容。更多信息请关注PHP中文网其他相关文章!

在PHP中,trait适用于需要方法复用但不适合使用继承的情况。1)trait允许在类中复用方法,避免多重继承复杂性。2)使用trait时需注意方法冲突,可通过insteadof和as关键字解决。3)应避免过度使用trait,保持其单一职责,以优化性能和提高代码可维护性。

依赖注入容器(DIC)是一种管理和提供对象依赖关系的工具,用于PHP项目中。DIC的主要好处包括:1.解耦,使组件独立,代码易维护和测试;2.灵活性,易替换或修改依赖关系;3.可测试性,方便注入mock对象进行单元测试。

SplFixedArray在PHP中是一种固定大小的数组,适用于需要高性能和低内存使用量的场景。1)它在创建时需指定大小,避免动态调整带来的开销。2)基于C语言数组,直接操作内存,访问速度快。3)适合大规模数据处理和内存敏感环境,但需谨慎使用,因其大小固定。

PHP通过$\_FILES变量处理文件上传,确保安全性的方法包括:1.检查上传错误,2.验证文件类型和大小,3.防止文件覆盖,4.移动文件到永久存储位置。

JavaScript中处理空值可以使用NullCoalescingOperator(??)和NullCoalescingAssignmentOperator(??=)。1.??返回第一个非null或非undefined的操作数。2.??=将变量赋值为右操作数的值,但前提是该变量为null或undefined。这些操作符简化了代码逻辑,提高了可读性和性能。

CSP重要因为它能防范XSS攻击和限制资源加载,提升网站安全性。1.CSP是HTTP响应头的一部分,通过严格策略限制恶意行为。2.基本用法是只允许从同源加载资源。3.高级用法可设置更细粒度的策略,如允许特定域名加载脚本和样式。4.使用Content-Security-Policy-Report-Only头部可调试和优化CSP策略。

HTTP请求方法包括GET、POST、PUT和DELETE,分别用于获取、提交、更新和删除资源。1.GET方法用于获取资源,适用于读取操作。2.POST方法用于提交数据,常用于创建新资源。3.PUT方法用于更新资源,适用于完整更新。4.DELETE方法用于删除资源,适用于删除操作。

HTTPS是一种在HTTP基础上增加安全层的协议,主要通过加密数据保护用户隐私和数据安全。其工作原理包括TLS握手、证书验证和加密通信。实现HTTPS时需注意证书管理、性能影响和混合内容问题。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

Dreamweaver Mac版
视觉化网页开发工具

禅工作室 13.0.1
功能强大的PHP集成开发环境

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

SublimeText3汉化版
中文版,非常好用