0

0

php框架中的动态实例化对象详解

伊谢尔伦

伊谢尔伦

发布时间:2017-06-26 14:09:32

|

3025人浏览过

|

来源于php中文网

原创

在框架开发,模块化开发等场合,我们可能有一种需求,那就是在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)动态决定(由变量决定)需要实例化什么样的对象,而不是直接写死在代码里。

通过上述例子我们已经知道了如何在运行时动态调用一个函数了,在现在面向对向如此流行的今天,在一些代码中,我们需要去动态去实例化一个类,该怎么做呢?

情况一:类的构造函数没有参数或参数的个数是确定的

立即学习PHP免费学习笔记(深入)”;

如果类的构造函数没有参数或者我们要实例化的类根本没有构造函数,似乎简单一点,可以照上面的例子改一个嘛,嗯,照葫芦画瓢,谁不会:

代码示例:(构造函数没有参数)

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
'; 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
'; 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
'; echo '$this->a=', $this->a, ', $this->b=', $this->b; } }

我们想要一个通用的方式来实例化这两个类。我们注意到FOO类是没有写构造函数的,或者是可以认为FOO类的构造函数的参数个数为零;而BAR类的构造函数却有参数。还好,PHP5已经足够强大了,引入了反射的概念,具体请参考PHP手册:反射,虽然手册上也没有什么可参考的:)。还好,命名写得不错,从类名和方法名上面已经可以看出大概的端倪,不需要太多的文字。

那么好吧,就让我们用PHP5的反射来着手这个事情:

PHP Apache和MySQL 网页开发初步
PHP Apache和MySQL 网页开发初步

本书全面介绍PHP脚本语言和MySOL数据库这两种目前最流行的开源软件,主要包括PHP和MySQL基本概念、PHP扩展与应用库、日期和时间功能、PHP数据对象扩展、PHP的mysqli扩展、MySQL 5的存储例程、解发器和视图等。本书帮助读者学习PHP编程语言和MySQL数据库服务器的最佳实践,了解如何创建数据库驱动的动态Web应用程序。

下载

(还在用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, '
'; 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);
}

好了,至于效果是什么,就麻烦各位看官自己动动手,运行一下看看,是不是自己期望的结果。

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
excel制作动态图表教程
excel制作动态图表教程

本专题整合了excel制作动态图表相关教程,阅读专题下面的文章了解更多详细教程。

20

2025.12.29

freeok看剧入口合集
freeok看剧入口合集

本专题整合了freeok看剧入口网址,阅读下面的文章了解更多网址。

65

2025.12.29

俄罗斯搜索引擎Yandex最新官方入口网址
俄罗斯搜索引擎Yandex最新官方入口网址

Yandex官方入口网址是https://yandex.com;用户可通过网页端直连或移动端浏览器直接访问,无需登录即可使用搜索、图片、新闻、地图等全部基础功能,并支持多语种检索与静态资源精准筛选。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

197

2025.12.29

python中def的用法大全
python中def的用法大全

def关键字用于在Python中定义函数。其基本语法包括函数名、参数列表、文档字符串和返回值。使用def可以定义无参数、单参数、多参数、默认参数和可变参数的函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

16

2025.12.29

python改成中文版教程大全
python改成中文版教程大全

Python界面可通过以下方法改为中文版:修改系统语言环境:更改系统语言为“中文(简体)”。使用 IDE 修改:在 PyCharm 等 IDE 中更改语言设置为“中文”。使用 IDLE 修改:在 IDLE 中修改语言为“Chinese”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

16

2025.12.29

C++的Top K问题怎么解决
C++的Top K问题怎么解决

TopK问题可通过优先队列、partial_sort和nth_element解决:优先队列维护大小为K的堆,适合流式数据;partial_sort对前K个元素排序,适用于需有序结果且K较小的场景;nth_element基于快速选择,平均时间复杂度O(n),效率最高但不保证前K内部有序。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

12

2025.12.29

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

134

2025.12.29

抖音网页版入口在哪(最新版)
抖音网页版入口在哪(最新版)

抖音网页版可通过官网https://www.douyin.com进入,打开浏览器输入网址后,可选择扫码或账号登录,登录后同步移动端数据,未登录仅可浏览部分推荐内容。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

63

2025.12.29

快手直播回放在哪看教程
快手直播回放在哪看教程

快手直播回放需主播开启功能才可观看,主要通过三种路径查看:一是从“我”主页进入“关注”标签再进主播主页的“直播”分类;二是通过“历史记录”中的“直播”标签页找回;三是进入“个人信息查阅与下载”里的“直播回放”选项。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

18

2025.12.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 8.1万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 6.9万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号