惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog RSS Feed
D
Darknet – Hacking Tools, Hacker News & Cyber Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
G
Google Developers Blog
MyScale Blog
MyScale Blog
Google DeepMind News
Google DeepMind News
J
Java Code Geeks
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
Check Point Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
P
Proofpoint News Feed
D
Docker
Jina AI
Jina AI
博客园 - 三生石上(FineUI控件)
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Help Net Security
Help Net Security
Google DeepMind News
Google DeepMind News
L
LINUX DO - 最新话题
T
Tailwind CSS Blog
N
Netflix TechBlog - Medium
Forbes - Security
Forbes - Security
MongoDB | Blog
MongoDB | Blog
Attack and Defense Labs
Attack and Defense Labs
Webroot Blog
Webroot Blog
A
About on SuperTechFans
Schneier on Security
Schneier on Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
Microsoft Azure Blog
Microsoft Azure Blog
F
Fortinet All Blogs
IT之家
IT之家
The Last Watchdog
The Last Watchdog
腾讯CDC
Microsoft Security Blog
Microsoft Security Blog
Project Zero
Project Zero
B
Blog
Recorded Future
Recorded Future
博客园_首页
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
SegmentFault 最新的问题
Security Archives - TechRepublic
Security Archives - TechRepublic
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Hacker News: Front Page
T
Threatpost
H
Heimdal Security Blog
Cloudbric
Cloudbric
Google Online Security Blog
Google Online Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog

SegmentFault 程序员就要好好玩最新的文章

亚马逊的技术哲学 11月初的美国之旅 -- 参加微软的 Microsoft Ignite 2019 JavaScript 初学者教程(指南) 如何学习一门新的语言 思路清奇:通过 JavaScript 获取移动设备的型号 一些关于Logecho的新动态 利用dns解析来实现网站的负载均衡 服务器被sfewfesfs病毒攻击 从一些小白问题想到的 使用phar上线你的代码包 Ruby学习第一天 从如何获取可信赖的ip地址聊起 新版 SegmentFault 重构之系统架构 一个用于web开发的泛域名 如何优雅地连接ssh 我是如何看简历的 靠谱的前端工程师在哪里 怎么样使用 Redis 来存储和查询 ip 数据 邮件发送服务AWS SES,Mailgun以及SendCloud 用PHP实现一个Amazon SES的代理服务器 在MySQL字段中使用逗号分隔符
PHP 5.6新特性之一:内部操作符重载
joyqi · 2014-03-13 · via SegmentFault 程序员就要好好玩最新的文章

转载自我的博客: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的函数命名就够混乱了。。。再重载成操作符,以后咋跟踪代码。。。