资讯专栏INFORMATION COLUMN

PHP 5.6新特性之一:内部操作符重载

canopus4u / 662人阅读

摘要:转载自我的博客在众多的新特性中,我觉得这是最神奇甚至是诡异的一个,如果有不理解这个概念的朋友,可能连它的说明都看不懂。在这个例子中操作符被重载为,操作符被重载为。再重载成操作符,以后咋跟踪代码。。。

  

转载自我的博客:http://70.io/2014/03/php-5_6-internal-operator-overloading

在众多php 5.6的新特性中,我觉得这是最神奇甚至是诡异的一个,如果有不理解这个概念的朋友,可能连它的说明都看不懂 https://wiki.php.net/rfc/operator_overloading_gmp。

首先要说明的是,这个重载不影响userland,也就是我们不用关心它是怎么重载的,只用关心怎么使用,它的实现是在php内核代码中。

在上面的php说明网址中,它举了一个对gmp_*模块重载后的例子

// 重载前的代码
$result = gmp_mod(
    gmp_add(
        gmp_mul($c0, gmp_mul($ms0, gmp_invert($ms0, $n0))),
        gmp_add(
            gmp_mul($c1, gmp_mul($ms1, gmp_invert($ms1, $n1))),
            gmp_mul($c2, gmp_mul($ms2, gmp_invert($ms2, $n2)))
        )
    ),
    gmp_mul($n0, gmp_mul($n1, $n2))
);

// 重载后的代码
$result = (
    $c0 * $ms0 * gmp_invert($ms0, $n0)
  + $c1 * $ms1 * gmp_invert($ms1, $n1)
  + $c2 * $ms2 * gmp_invert($ms2, $n2)
) % ($n0 * $n1 * $n2);

如果你会一点scala类似的语言,就能很好地理解了。在这个例子中+操作符被重载为gmp_add*操作符被重载为gmp_mull。以前的基于函数式的代码让很多算法上的细节无法展现出来,改成基于操作符的就很好理解了。

它是怎么实现的呢?让我们来跟踪一下这个patch修改的源代码,https://github.com/php/php-src/pull/342/files。最好先关注Zend/zend_operators.c这个文件的修改,基本上逻辑就很清晰了,比如ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)这个函数,它处理了php中的加号+运算(前面带+的两行是这个patch增加的内容)

            default:
                if (!converted) {
 +                  ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB);
 +
                    zendi_convert_scalar_to_number(op1, op1_copy, result);
                    zendi_convert_scalar_to_number(op2, op2_copy, result);
                    converted = 1;

if(!converted)判断了左右操作数还没有转换为number时候的处理,在以前是调用zendi_convert_scalar_to_number直接将其转换为number然后再SUB,现在在前面加了个宏ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB),这个宏的实现细节是

#define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode)                                                  
    if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation)) {                       
        if (SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) {  
            return SUCCESS;                                                                       
        }                                                                                         
    } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, do_operation)) {                
        if (SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) {  
            return SUCCESS;                                                                       
        }                                                                                         
    }

它先判断左操作数是否为一个OBJECT,并且这个OBJECT内部定义了运算符操作的重载实现,如果是那么就调用这个handler来处理这次操作符运算,如果左操作数不符合这些条件,再对右操作数做一次这些判断,基本上$a + $b你就可以理解为以下伪代码

if ($a instanceof GMP && method_exists($a, "add")) {
    $a->add($b);
} else if ($b instanceof GMP && method_exists($b, "add")) {
    $b->add($a);
}

好吧,最后我来谈谈我的看法,之所以我对这个改进感到诡异是因为,它对一般的web开发基本没啥用,其影响基本是很少用到的数学运算模块。而且由于这个改进跟userland没啥关系,所以我们在php代码中也用不了,别指望你能像scala那样在class里定义操作符的实现,这完全是两码事。

你只能指望这些模块或者扩展的作者实现了,而且最后实现也没有一个统一的标准,本来php的函数命名就够混乱了。。。再重载成操作符,以后咋跟踪代码。。。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/20695.html

相关文章

  • php易错笔记-类与对象,命名空间

    摘要:类与对象基本概念如果在之后跟着的是一个包含有类名的字符串,则该类的一个实例被创建。如果该类属于一个名字空间,则必须使用其完整名称。如果一个类被声明为,则不能被继承。命名空间通过关键字来声明。 类与对象 基本概念 new:如果在 new 之后跟着的是一个包含有类名的字符串,则该类的一个实例被创建。如果该类属于一个名字空间,则必须使用其完整名称。 Example #3 创建一个实例 ...

    MartinHan 评论0 收藏0
  • PHP经验总结 - 聊聊面向对象

    摘要:例如汽车这个名词可以理解为汽车的总类,但这辆宝马汽车则是一个具体的汽车对象。当在类成员方法内部调用的时候,可以使用伪变量调用当前对象的属性。在面向对象中则被称之为方法。 简述 现在大伙都在讲面向对象编程,但是我们也得先找着一个对象是不?不然怎么面向对象?怎么编程? --- 笑话一则,但是理不亏,要搞P面向对象编程,我们起码要先搞懂对象(还有类)是什么?只有了解它,理解它,你才能驾驭它。...

    lpjustdoit 评论0 收藏0
  • PHP 7 值得期待的特性(上)

    摘要:然而,两个重要的已经获得通过,它们将带来一些期望已久的内部与用户层的一致性。综合比较运算符我个人最喜欢的新增特性是综合比较运算符,,也称为飞船操作符。实际上,该操作符的工作方式与,或基本一致。 这是我们期待已久的 PHP 7 系列文章的第一篇。 或许你已经知道了,我在 PHP 5.0.0 时间轴 提的 RFC (Request For Comments)通过了, PHP 7 成为 PH...

    msup 评论0 收藏0
  • PHP 5.3、5.4、5.5、5.6 中的特性

    摘要:同时还支持简写的运算符,表示进行幂运算并赋值。对应的结构为和。为了达到一致性将添加函数。新增函数可用来返回数组中指定的一列。这种简写形式被称为在起被默认开启,在起总是可用。三元运算符可以简写省略中间的部分表达式,当为时返回,否则返回。 PHP 5.6 1、可以使用表达式定义常量 https://php.net/manual/zh/migration56.new-features.p...

    ysl_unh 评论0 收藏0
  • PHP 5.3、5.4、5.5、5.6 中的特性(7出来但是一样有用)

    摘要:同时还支持简写的运算符,表示进行幂运算并赋值。为了达到一致性将添加函数。新增函数可用来返回数组中指定的一列。这种简写形式被称为在起被默认开启,在起总是可用。结构中可以用双引号来声明标识符了。 PHP 5.61、可以使用表达式定义常量 https://php.net/manual/zh/mig... 在之前的 PHP 版本中,必须使用静态值来定义常量,声明属性以及指定函数参数默认值。 现...

    Shihira 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<