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

推荐订阅源

博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
月光博客
月光博客
AI
AI
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
CXSECURITY Database RSS Feed - CXSecurity.com
WordPress大学
WordPress大学
GbyAI
GbyAI
L
Lohrmann on Cybersecurity
O
OpenAI News
Schneier on Security
Schneier on Security
P
Palo Alto Networks Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Troy Hunt's Blog
V2EX - 技术
V2EX - 技术
W
WeLiveSecurity
L
LINUX DO - 最新话题
人人都是产品经理
人人都是产品经理
S
Security Affairs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
A
Arctic Wolf
Recorded Future
Recorded Future
Microsoft Security Blog
Microsoft Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
GRAHAM CLULEY
N
Netflix TechBlog - Medium
TaoSecurity Blog
TaoSecurity Blog
C
Check Point Blog
Scott Helme
Scott Helme
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Apple Machine Learning Research
Apple Machine Learning Research
PCI Perspectives
PCI Perspectives
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Vercel News
Vercel News
The Hacker News
The Hacker News
Y
Y Combinator Blog
Latest news
Latest news
SecWiki News
SecWiki News
Hugging Face - Blog
Hugging Face - Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
Webroot Blog
Webroot Blog
Google DeepMind News
Google DeepMind News
Recent Commits to openclaw:main
Recent Commits to openclaw:main
C
Cisco Blogs
博客园_首页
H
Hackread – Cybersecurity News, Data Breaches, AI and More
宝玉的分享
宝玉的分享
L
LINUX DO - 热门话题

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