Repository navigation
Release Notes
Performance: Built-in function call optimisation (PHP 8.5)
Background
PHP 8.5's Zend compiler (zend_compile.c line 4975)
contains a function — zend_try_compile_special_func_ex — that compiles certain built-in calls
directly to single VM opcodes, completely bypassing the normal function-call overhead
(no frame push/pop, no argument marshalling, no symbol table lookup):
| Function(s) | Opcode emitted |
|---|---|
strlen |
ZEND_STRLEN |
is_null, is_bool, is_int, is_string, is_array, is_object, is_resource |
ZEND_TYPE_CHECK |
count / sizeof |
ZEND_COUNT |
in_array |
ZEND_IN_ARRAY |
array_slice |
ZEND_ARRAY_SLICE |
array_key_exists |
ZEND_ARRAY_KEY_EXISTS |
intval, strval, boolval, floatval / doubleval |
ZEND_CAST |
sprintf |
ZEND_FAST_CONCAT-like |
chr, ord |
ZEND_CHR / ZEND_ORD |
get_class, get_called_class, gettype |
ZEND_GET_CLASS / ZEND_GET_TYPE |
The catch: this intrinsification only fires when the call is resolved at compile time.
Inside a namespace (e.g. DariusIII\NetNntp\Protocol), an unqualified call like trim() forces
the engine to check at runtime whether DariusIII\NetNntp\Protocol\trim exists before falling back
to the global. Prefixing with \ eliminates that runtime lookup and allows the compiler to
intrinsify or use the faster frameless call path.
Changes
src/Protocol/Client.php
-
Added
\prefix to all unqualified built-in function calls, enabling compile-time resolution
and opcode intrinsification:
openssl_error_string,strlen,strpbrk,fwrite,fgets,stream_get_meta_data,
trim,substr,feof,str_ends_with,str_starts_with,str_replace,explode,
reset,next,stream_socket_client,stream_set_timeout,stream_set_read_buffer,
fclose,stream_socket_enable_crypto,ltrim,gmdate,implode,strcasecmp,
is_numeric,is_array,is_resource,is_string. -
Removed redundant
|| strlen($line) < 2branch in_getTextResponse().
str_ends_with($line, "\r\n")returningtruealready guaranteesstrlen ≥ 2, so the second
operand was dead code that emitted aZEND_STRLENopcode on every iteration of the hot
receive loop for no reason. -
Removed redundant
(string)cast onsubstr($response, 4)in_getStatusResponse().
substr()always returnsstringwhen given astringinput, so theZEND_CASTopcode
was emitted unnecessarily.
src/Client.php
- Added
\prefix to all unqualified built-in function calls:
implode,strtotime,substr,array_merge,array_keys,array_values,
array_combine,array_slice,array_fill,array_splice,strpos,ltrim,
ctype_digit,str_starts_with,str_ends_with,reset,preg_split,trim,
is_int,is_array,is_string,count.
Other housekeeping
- Removed legacy
package.xml(PEAR descriptor, superseded entirely bycomposer.json).