PHP7中的标量和严格类型是否具有性能增强功能? [英] Are scalar and strict types in PHP7 a performance enhancing feature?
问题描述
自PHP7以来,我们现在可以使用标量类型提示并按文件要求严格类型.使用这些功能有什么性能上的好处?如果是,怎么办?
Since PHP7 we can now use scalar typehint and ask for strict types on a per-file basis. Are there any performance benefits from using these features? If yes, how?
在互连网上,我只发现了一些概念上的好处,例如:
Around the interwebs I've only found conceptual benefits, such as:
- 更精确的错误
- 避免不必要的类型强制的问题
- 更多语义代码,避免了在使用他人代码时的误解
- 更好的IDE代码评估
推荐答案
如今,在PHP7中使用标量和严格类型并不能提高性能.
Today, the use of scalar and strict types in PHP7 does not enhance performance.
PHP7没有JIT编译器.
PHP7 does not have a JIT compiler.
如果将来某个时候PHP确实获得了JIT编译器,那么很难想象可以使用附加类型信息执行的优化.
If at some time in the future PHP does get a JIT compiler, it is not too difficult to imagine optimizations that could be performed with the additional type information.
在没有JIT的情况下进行优化时,标量类型只是部分有用.
When it comes to optimizations without a JIT, scalar types are only partly helpful.
让我们采用以下代码:
<?php
function (int $a, int $b) : int {
return $a + $b;
}
?>
这是Zend为此生成的代码:
This is the code generated by Zend for that:
function name: {closure}
L2-4 {closure}() /usr/src/scalar.php - 0x7fd6b30ef100 + 7 ops
L2 #0 RECV 1 $a
L2 #1 RECV 2 $b
L3 #2 ADD $a $b ~0
L3 #3 VERIFY_RETURN_TYPE ~0
L3 #4 RETURN ~0
L4 #5 VERIFY_RETURN_TYPE
L4 #6 RETURN null
ZEND_RECV
是对接收到的内容执行类型验证和强制转换的操作码参数.下一个操作码是 ZEND_ADD
:
ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMPVAR|CV, CONST|TMPVAR|CV)
{
USE_OPLINE
zend_free_op free_op1, free_op2;
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_LONG)) {
if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
result = EX_VAR(opline->result.var);
fast_long_add_function(result, op1, op2);
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
} else if (EXPECTED(Z_TYPE_INFO_P(op1) == IS_DOUBLE)) {
if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_DOUBLE)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_INFO_P(op2) == IS_LONG)) {
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
ZEND_VM_NEXT_OPCODE();
}
}
SAVE_OPLINE();
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op1) == IS_UNDEF)) {
op1 = GET_OP1_UNDEF_CV(op1, BP_VAR_R);
}
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(op2) == IS_UNDEF)) {
op2 = GET_OP2_UNDEF_CV(op2, BP_VAR_R);
}
add_function(EX_VAR(opline->result.var), op1, op2);
FREE_OP1();
FREE_OP2();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
不了解任何代码的作用,您会发现它相当复杂.
Without understanding what any of that code does, you can see that it's rather complex.
因此,目标将完全省略ZEND_RECV
,而将ZEND_ADD
替换为ZEND_ADD_INT_INT
,因为参数类型是已知的,因此无需执行任何检查(除了保护)或分支.
So the target would be omitting ZEND_RECV
completely, and replacing ZEND_ADD
with ZEND_ADD_INT_INT
which doesn't need to perform any checking (beyond guarding) or branching, because the types of params are known.
为了省略这些内容并使用ZEND_ADD_INT_INT
,您需要能够在编译时可靠地推断$a
和$b
的类型.编译时间推断有时很容易,例如$a
和$b
是文字整数或常量.
In order to omit those, and have a ZEND_ADD_INT_INT
you need to be able to reliably infer the types of $a
and $b
at compile time. Compile time inference is sometimes easy, for example, $a
and $b
are literal integers, or constants.
从字面上昨天,PHP 7.1的确非常相似:现在有一些针对特定类型的处理程序,频率操作码,如ZEND_ADD
. Opcache能够推断某些变量的类型,甚至在某些情况下甚至能够推断数组中变量的类型,并更改生成的操作码以使用普通的ZEND_ADD
来使用特定于类型的处理程序:
Literally yesterday, PHP 7.1 got something really similar: There are now type specific handlers for some high frequency opcodes like ZEND_ADD
. Opcache is able to infer the type of some variables, it's even able to infer the types of variables within an array in some cases and change opcodes generated to use the normal ZEND_ADD
, to use a type specific handler:
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = EX_VAR(opline->result.var);
ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
同样,在不了解其作用的情况下,您可以说这很容易执行.
Again, without understanding what any of that does, you can tell that this is much simpler to execute.
这些优化非常酷,但是,当PHP具有JIT时,最有效,最有趣的优化就会出现.
These optimizations are very cool, however, the most effective, and most interesting optimizations will come when PHP has a JIT.
这篇关于PHP7中的标量和严格类型是否具有性能增强功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!