首页 后端开发 php教程 给猪的鼻子插一根葱_PHP

给猪的鼻子插一根葱_PHP

Jun 01, 2016 pm 12:42 PM
object pro 对象

PHP 具备一些动态语言的特征, 但不彻底. 虽然 PHP 的标志是一头大象, 可这头象的鼻子未免太短, 以致经常够不着东西, 反而象猪了. 本文旨在探讨一种使 PHP 更动态化的方法, 主要是模拟 Javascript 的 prototype 继承. 既然是模拟, 就不是真的能使 PHP 动态起来, 只是插上一根葱, 让它装得更"象"一点.

一. 基本操作
通过 Javascript 的 prototype 动态地为对象添加属性, 我们可以这样:

Object.prototype.greeting = 'Hello'
var o = new Object
alert(o.greeting)
登录后复制

Js 的内置对象 Object 可看作一个"类", 任何 Js "类"都有 prototype 内置对象, 用 PHP 来模拟它可以是:
error_reporting(E_ALL);

class Object
{
     public static $prototype;

     protected function __get($var) {
         if ( isset(self::$prototype->$var) ) {
             return self::$prototype->$var; }}
}
登录后复制

然后我们可以:
Object::$prototype->greeting = 'Hello';
$o = new Object;
echo $o->greeting; // 输出 Hello
登录后复制

这里利用了 PHP 的自动转型特性. 在 PHP 中, 我们要声明一个数组, 并不需要先 $var = array() 然后才做 $var[] = some_value, 直接地使用后者就可以得到一个数组; 同样地直接 $object->var 的时候, $object 就被自动定义为 stdClass 对象. 这就解决了在定义类内静态属性时不能声明 public static $prototype = new stdClass 的问题.

在 Js 中给"类"动态添加方法:
Object.prototype.say = function(word) { alert(word) }
o.say('Hi')
登录后复制

在 PHP 中模拟:
error_reporting(E_ALL);

class Object
{
     public static $prototype;

     protected function __get($var) {
         if ( isset(self::$prototype->$var) ) {
             return self::$prototype->$var; }}

     protected function __call($call, $params) {
         if ( isset(self::$prototype->$call) && is_callable(self::$prototype->$call) ) {
             return call_user_func_array(self::$prototype->$call, $params); }
         else {
             throw new Exception('Call to undefined method: ' . __CLASS__ . "::$call()"); }}
}
登录后复制

这样, 就可以
Object::$prototype->say = create_function('$word', 'echo $word;');
$o->say('Hi');
登录后复制

但是 PHP 的 create_function 返回的结果并不等同于 Js 中的 Function 对象, Js 的 Function 对象是一种闭包(closure), 它可以直接调用宿主的属性, 如
Object.prototype.rock = function() { alert(this.oops) }
o.oops = 'Oops'
o.rock()
登录后复制

但是在 PHP 中我们不可以写
Object::$prototype->rock = create_function('', 'echo $this->oops;');
$o->oops = 'Oops';
$o->rock();
登录后复制

会报告 Fatal error: Using $this when not in object context, 因为 create_function 返回的是匿名的普通函数, 它没有宿主. 为解决这个问题, 我们需要在参数中传入对象本身, 而且不能使用 $this 变量名做参数, 我们暂时用一个 $caller 的变量名:
Object::$prototype->rock = create_function('$caller', 'echo $caller->oops;');
$o->oops = 'Oops';
$o->rock($o);
登录后复制

现在可以了, 可是看上去怪怪的, 一点都不像动态语言. 嗯~, 这根葱还是有点短, 还是不"象".

问题来了:
1. 在调用动态方法时需要传递对象本身, 这算哪门子的面向对象?
2. 我们要在代码中使用 $this, 这才象是在面向对象.

解决方法:
1. 重新写一个函数代替 create_function, 在参数部分挤一个参数 $that 进去作为第一个参数, 在 __call 中向匿名函数传递参数时加入对象本身 $this 作为第一参数.
2. 允许在代码中使用 $this, 我们在代替函数中把 $this 换成 $that.

我们给它添加一个 create_method 函数来代替 create_function
function create_method($args, $code) {
     if ( preg_match('/\$that\b/', $args) ) {
         throw new Exception('Using reserved word \'$that\' as argument'); }
     $args = preg_match('/^\s*$/s', $args) ? '$that' : '$that, '. $args;
     $code = preg_replace('/\$this\b/', '$that', $code);
     return create_function($args, $code); }
登录后复制

$that 作为参数中的"保留字", 当出现在参数部分中将抛出异常.(在 PHP5 的早期暗夜版本中, $that 也曾经是保留字)

相应地, Object 中的 __call 也要作出改动
class Object
{
     public static $prototype;

     protected function __get($var) {
         if ( isset(self::$prototype->$var) ) {
             return self::$prototype->$var; }}

     protected function __call($call, $params) {
         if ( isset(self::$prototype->$call) && is_callable(self::$prototype->$call) ) {
             array_unshift($params, $this); // 这里!
             return call_user_func_array(self::$prototype->$call, $params); }
         else {
             throw new Exception('Call to undefined method: ' . __CLASS__ . "::$call()"); }}
}
登录后复制

现在我们就可以
Object::$prototype->rock = create_method('', 'echo $this->oops;');
$o->oops = 'Oops';
$o->rock();
登录后复制





二. 继承
面向对象的一大特征是继承, 继承最大限度地保留代码重用能力. 但如果直接用上例的 Object 类去创建继承类则会出错, 因为
1. 子类继承的静态属性 $prototype 永远属于父类(不管 $prototype 是标量还是列表, 对象更不消说)
2. 如果子类所继承的方法中有 self 关键字, self 会指向父类而非子类
class Object
{
     public static $prototype;

     protected function __get($var) {
         ... }

     protected function __call($call, $params) {
         ... }
}

class Test extends Object
{
}

Test::$prototype->greeting = 'Hello';
print_r(Object::$prototype);
/* outputs
stdClass Object
(
    [greeting] => Hello
)
*/

Test::$prototype->say = create_method('$word', 'echo $word;');
$o = new Object;
$o->say('Hi');
/* outputs
Hi
*/
登录后复制

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

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

小米平板6和pro哪个值得入手 小米平板6和pro哪个值得入手 Feb 07, 2024 pm 08:36 PM

许多用户都不太清楚小米平板6和pro哪个值得入手,从配置来看,肯定是Pro的更高配置是推荐的,但也要综合价格和自己的预算来看,不同的产品定位的人群也是不同的。小米平板6和pro哪个值得入手答:小米平板6Pro会更好,不管是性能还是拍照续航都会更好。1、处理器小米平板6:骁龙870小米平板6Pro:性能更强大的骁龙第一代骁龙8+处理器2、电池大小小米平板6:8840mAh,67W秒充小米平板6Pro:8600mAh,33W快充小米平板6的续航上表现会更加的优秀,但是充电会比较慢。3、拍照小米平板6

iPhone 15 Pro Max vs iPhone 14 Pro Max:它们之间的对比和区别是什么? iPhone 15 Pro Max vs iPhone 14 Pro Max:它们之间的对比和区别是什么? Sep 19, 2023 pm 08:29 PM

iPhone15Pro与iPhone14Pro:规格比较以下是iPhone15ProMax和iPhone14ProMax的规格比较:iPhone15ProMaxiPhone14ProMax显示尺寸6.7英寸6.7英寸显示技术超级视网膜XDROLED超级视网膜XDROLED分辨率2796x1290像素,460ppi2796x1290像素,460ppi刷新率120赫兹120赫兹峰值亮度2,000尼特2,000尼特尺寸6.29x3.02x0.32英寸6.33x3.06x0.31英寸重量221克240克

如何启动小米手环8pro 如何启动小米手环8pro Jan 14, 2024 am 08:51 AM

不少用户在第一次接触使用小米手环8的时候不知道该怎么操作使用开机,其实方法也很简单,我们只需要找到USB数据线然后把手表和电源连接起来,然后冲一段时间电以后就可以按键开机了。小米手环8pro怎么开机1、首先把手表安装好,就是把主题和表带两边对接连上。2、然后我们第一次开机是需要连接充电线的,连接方法就在手表底部。3、等待手表震动一下就可以进行开机了,随后就可以和你的手机进行连接了。>>>

使用PHP的json_encode()函数将数组或对象转换为JSON字符串 使用PHP的json_encode()函数将数组或对象转换为JSON字符串 Nov 03, 2023 pm 03:30 PM

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式,已经成为Web应用程序之间数据交换的常用格式。PHP的json_encode()函数可以将数组或对象转换为JSON字符串。本文将介绍如何使用PHP的json_encode()函数,包括语法、参数、返回值以及具体的示例。语法json_encode()函数的语法如下:st

macbookair和pro的区别 macbookair和pro的区别 Feb 08, 2024 am 09:57 AM

macbookair是苹果的一款笔记本电脑,很多用户好奇macbookair和pro之间,有哪些区别,这两个笔记本在处理器核心,主频以及显卡类型上都有一些区别。macbookair和pro的区别:1、处理器核心,线程不同:macbookair的处理器拥有双核心,四线程。而Pro比macbookair更强大,拥有四核心,八线程。2、处理器主频不同:macbookair的处理器是1.6GHz的主频。pro的处理器主频是1.4GHz,比macbookair低了一些。3、显卡不同:macbookair采

小米Pro14发布日期 小米Pro14发布日期 Jan 05, 2024 pm 02:50 PM

小米pro14已经上市,而且它的配置作为商务办公本来说也是非常不错的了,而且还有三种处理器配置可以选择,价格也不是特别高。很多小伙伴不知道小米Pro14的具体上市时间。小米pro14上市时间答:2021年11月10日小米Pro14锐龙版开启预约,首发价5299元起。2022年7月4日,小米笔记本Pro14发布,7月8日零点正式开售。小米pro14介绍1、屏幕配备14英寸2.5K超视网膜屏,分辨率为2560x1600,屏占比高达88%,拥有100%sRGB色域,刷新率为120Hz。2、外观采用6系

三摄加持 20 倍变焦,荣耀亲选小湃智能摄像头 Pro 创新来袭 三摄加持 20 倍变焦,荣耀亲选小湃智能摄像头 Pro 创新来袭 Aug 23, 2024 pm 09:44 PM

您家里装摄像头了吗?近些年,家用摄像头产品一下就成了爆款。我问了身边的小伙伴们,好家伙~居然每家都有,甚至有的还不止一台。但随着产品的普及,也随之带来了一些使用过程中的吐槽点。比如同一时间只能看到一个地方,再想看其他地方还得来回调整云台旋转摄像头,观看画面有一定的盲区和时间差;或者想仔细看看家中某个位置时,发现画面模糊根本看不清晰;等等......在体验上大打折扣。荣耀亲选与小湃科技共同推出荣耀亲选小湃智能摄像头Pro主打"三镜头双画面"。为行业及用户痛点提供了全新的解决思路

苹果A17 Pro GPU将带来什么变化? 苹果A17 Pro GPU将带来什么变化? Sep 18, 2023 pm 08:53 PM

苹果继续推动技术的界限,其创新的最新证明是苹果A17ProGPU的推出。这个尖端组件拥有完全重新设计的GPU,有望在性能、图形和用户体验方面取得显着改进。苹果A17ProGPU,推出与iPhone15Pro一起,是半导体工程的奇迹。它采用3nm工艺制造,代表了小型化的重大飞跃,将比以往更多的晶体管封装到单个芯片中。这一技术壮举转化为更高的电源效率和计算能力。苹果A17ProGPU提供令人惊叹的图形A17Pro芯片的突出特点之一是其重新设计的GPU。Apple在优化图形性能方面投入了大量资金,使其

See all articles