侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

PHP:在对象上动态添加一个新的方法

php  /  管理员 发布于 2年前   164

有关在一个对象上动态添加方法,如果你来自Ruby语言或您熟悉这门语言,你已经知道它是什么...... Ruby提供给你一种方式来获得一个instancied对象,并给这个对象添加一个额外的方法。

 

好!不说Ruby了,让我们来谈谈PHP

 

PHP未提供一个“标准的方式”做这样的事情,这也是没有核心的一部分...

 

但无论如何,它并没有说我们不能做这样的事情。

 

因此,让我们看一下代码,我将展示两个实现:一是使用PHP 5.3,另一个使用PHP5.4,这些例子充分利用在PHP 5.3版本中增加的匿名函数(闭包),并且也利用闭包类的优势以及在5.4版本添加的方法绑定。

 

在PHP 5.3中添加方法的对象

 

 

/** * Example in PHP 5.3  */class Meta{        private $methods = array();    public function addMethod($methodName, $methodCallable)    {        if (!is_callable($methodCallable)) {            throw new InvalidArgumentException('Second param must be callable');        }        $this->methods[$methodName] = $methodCallable;    }    public function __call($methodName, array $args)    {        if (isset($this->methods[$methodName])) {            array_unshift($args, $this);            return call_user_func_array($this->methods[$methodName], $args);        }        throw RunTimeException('There is no method with the given name to call');    }}

 

 

 

/** * Example in PHP 5.3  */require 'Meta.php';$meta = new Meta();$meta->addMethod('color', function ($self) {    $self->name = 'My Name';    return '#00000';});echo $meta->color(), PHP_EOL;echo $meta->name, PHP_EOL;

 GitHub 的链接 https://gist.github.com/krolow/4189729#file-meta-php

 

它是如何工作的?

它使匿名函数和魔术方法__call,该类元有方法addMethod的使用,这种方法是等待两个参数,第一个是方法名,第二个可调用匿名函数。

 

每次调用原始对象没有(未在类中声明)的方法,该方法调用一下,函数调用将寻找你是否有给定名称注册一个新的方法,如果是,它调用匿名函数,传参数给当前对象的匿名函数,所以你可以访问类的方法和属性。

 

它有一定的局限性,你将不能访问私有的方法和属性,但它有可能使用象反射这样的方法来处理。

 

在PHP5.4中添加方法的对象

trait MetaTrait{        private $methods = array();     public function addMethod($methodName, $methodCallable)    {        if (!is_callable($methodCallable)) {            throw new InvalidArgumentException('Second param must be callable');        }        $this->methods[$methodName] = Closure::bind($methodCallable, $this, get_class());    }     public function __call($methodName, array $args)    {        if (isset($this->methods[$methodName])) {            return call_user_func_array($this->methods[$methodName], $args);        }         throw new RunTimeException('There is no method with the given name to call');    } }

  

 

require 'MetaTrait.php';class HackThursday {    use MetaTrait;    private $dayOfWeek = 'Thursday';}$test = new HackThursday();$test->addMethod('when', function () {    return $this->dayOfWeek;});echo $test->when();

 

 

GitHub中的链接:https://gist.github.com/krolow/4264062#file-test-php

 

正如你所看到的第二个例子让使用trait,PHP5.4的另一项新功能,这样一来我们使模向合成,这是一个好主意,更解耦你的代码。

 

trait作为与PHP 5.3的类Meta.php颇为相似,也是对象的用法,这里的区别是,当添加方法时你匿名函数不再需要接收的对象实例作为参数,正如你在测试的例子可以看到的,并且你能够直接访问$this引用的对象的方法和属性,这就是可能的,因为有Closure::bind,,因为有这一招,我们能够注入对象,将通过传参添加方法的匿名函数放到内部范围。所以一旦你调用该方法,它是动态创建的,我们调用的闭包是在你添加方法时存储在内存中的,并且闭包是与实例在同一范围的。所以我们现在能够访private属性, protected等...并它看起来也更好一点,因为我们并不需要强制的第一个参数是对象的实例。

 

我到底为什么要用它呢?

 

这只是动态添加方法的一种实践,当你想创造更通用的东西,或为你代码的API创建一个漂亮的接口,它给出了一些灵活性。但是必须注意很重要的一点,也许坏的程序员用这样类似的方法可以做出让人发疯的东西。

 

 

原文网址:

http://cobaia.net/php/2012/12/12/php-adding-a-new-method-to-an-object-on-the-fly/

 

 

 


  • 上一条:
    php中隐形字符65279(utf-8的BOM头)问题
    下一条:
    PHP如果自带一个小型的web服务器就好了
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在PHP 8.3版本中json_validate跟json_decode函数对比浅析(0个评论)
    • 在PHP语言中class类自动加载相关文件浅析(0个评论)
    • PHP 8.2版本发布(0个评论)
    • 最新版PHP 8.2中的弃用情况(0个评论)
    • 在php开发商品sku功能时实现批量生成sku组合的两种方式介绍(0个评论)
    • 近期文章
    • 在Laravel应用程序如何减少代码重复编写(0个评论)
    • 在laravel项目中提高安全性方式推荐:CSP内容安全策略(0个评论)
    • 在go语言中从值中获取常量名称代码示例(0个评论)
    • 在go语言中如何通过名称获得结构字段和值代码示例(0个评论)
    • 在go语言中用JQuery + html2canvas实现拍摄浏览器的屏幕截图示例(0个评论)
    • 人生感悟分享:讲一个大学毕业生到社畜老狗的蜕变心路历程(0个评论)
    • laravel9框架报错Target class... does not exist解决方式(0个评论)
    • Laravel 9.48版本发布(0个评论)
    • Meta高级工程师现身说法:程序员干得越久,代码写得越少?(0个评论)
    • 本站zongscan祝大家除夕快乐,2023有奔头(0个评论)
    • 近期评论
    • 博主 在

      2023年国务院办公厅春节放假通知:1月21日起休7天中评论 @ xiaoB 你只管努力,剩下的叫给天意;天若有情天亦老,..
    • xiaoB 在

      2023年国务院办公厅春节放假通知:1月21日起休7天中评论 会不会春节放假后又阳一次?..
    • BUG4 在

      你翻墙过吗?国内使用vpn翻墙可能会被网警抓,你需了解的事中评论 不是吧?..
    • 博主 在

      go语言+beego框架中获取get,post请求的所有参数中评论 @ t1  直接在router.go文件中配就ok..
    • Jade 在

      如何在MySQL查询中获得当月记录中评论 Dear zongscan.com team, We can skyroc..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-11
    • 2017-12
    • 2018-01
    • 2018-02
    • 2018-03
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-09
    • 2021-02
    • 2021-03
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客