Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ext/standard/BuiltinIntrospectionPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public static function functionIsAdvertised(string $functionName): bool
if ('crc32c' === $lc) {
return CompilerVersion::advertisesCrc32c();
}
if ('hebrevc' === $lc) {
return CompilerVersion::advertisesHebrevc();
}
if (\in_array($lc, [
'array_any',
'array_all',
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ public function getFunctions(): array
new soundex(),
new metaphone(),
new hebrev(),
new hebrevc(),
...(CompilerVersion::supportsHebrevc() ? [new hebrevc()] : []),
...(CompilerVersion::supportsConvertCyrString() ? [new convert_cyr_string()] : []),
new strnatcmp(),
new strnatcasecmp(),
Expand Down
134 changes: 108 additions & 26 deletions lib/CompilerVersion.php
Original file line number Diff line number Diff line change
Expand Up @@ -367,21 +367,25 @@ public static function advertisesStrIncrement(): bool
/**
* PHP 8.3+ class_uses_recursive() (ext/standard/basic_functions.c, issue #6469, #12816, #16708).
*
* Enabled by default on the 8.4.0-dev toolchain (runtime reports 8.4; php-src has the builtin since 8.3).
* `PHP_COMPILER_PROFILE=8.2` (or older) keeps the Zend 8.2 reference gate (function absent).
* Withheld on 8.4.0-dev reference profile (matches Zend 8.2 function_exists gate). Enable via
* stable 8.4.0+ or explicit `PHP_COMPILER_PROFILE=8.3` / `8.4` forward profile.
*/
public static function supportsClassUsesRecursive(): bool
{
if (version_compare(self::VERSION, '8.3', '<')) {
return false;
}

if (version_compare(self::VERSION, '8.4.0', '>=')) {
return true;
}

$raw = getenv('PHP_COMPILER_PROFILE');
if (\is_string($raw) && '' !== trim($raw)) {
return version_compare(self::languageProfileVersion(), '8.3.0', '>=');
if (!\is_string($raw) || '' === trim($raw)) {
return false;
}

return self::advertisesBuiltinSince('8.3.0');
return version_compare(self::languageProfileVersion(), '8.3.0', '>=');
}

/**
Expand Down Expand Up @@ -961,27 +965,40 @@ public static function supportsClassHasFunctions(): bool
* PHP 8.4+ attribute_exists(), class_meth_exists(), unitenum_exists()
* (ext/reflection/php_reflection.c, ext/standard/basic_functions.c; #14995, #15692, #17138).
*
* Default 8.4.0-dev toolchain registers the builtins; withheld when
* {@see languageProfileVersion()} is below 8.4.0 (e.g. `PHP_COMPILER_PROFILE=8.2`).
* Withheld on 8.4.0-dev reference profile (matches Zend 8.2 function_exists gate). Enable via
* stable 8.4.0+ or explicit `PHP_COMPILER_PROFILE=8.4` forward profile.
*/
public static function supportsPhp84ReflectionProbeBuiltins(): bool
{
if (version_compare(self::VERSION, '8.4', '<')) {
return false;
}

if (version_compare(self::VERSION, '8.4.0', '>=')) {
return true;
}

$raw = getenv('PHP_COMPILER_PROFILE');
if (\is_string($raw) && '' !== trim($raw)) {
return version_compare(self::languageProfileVersion(), '8.4.0', '>=');
if (!\is_string($raw) || '' === trim($raw)) {
return false;
}

return version_compare(self::builtinAdvertisementVersion(), '8.4.0', '>=');
return version_compare(self::languageProfileVersion(), '8.4.0', '>=');
}

/** attribute_exists()/class_meth_exists()/unitenum_exists() visible to function_exists() — same gate as {@see supportsPhp84ReflectionProbeBuiltins()}. */
/** attribute_exists()/class_meth_exists()/unitenum_exists() visible to function_exists() — stable runtime or forward 8.4+ (#17206). */
public static function advertisesPhp84ReflectionProbeBuiltins(): bool
{
return self::supportsPhp84ReflectionProbeBuiltins();
if (version_compare(self::VERSION, '8.4.0', '>=')) {
return true;
}

$raw = getenv('PHP_COMPILER_PROFILE');
if (!\is_string($raw) || '' === trim($raw)) {
return false;
}

return version_compare(self::languageProfileVersion(), '8.4.0', '>=');
}

/**
Expand Down Expand Up @@ -1593,29 +1610,42 @@ public static function supportsArrayPadPadType(): bool
/**
* PHP 8.4+ mb_trim/ltrim/rtrim (ext/mbstring/mbstring.c, issue #11901, #12797, #9977, #17120).
*
* Default 8.4.0-dev toolchain registers the builtins; withheld when
* {@see languageProfileVersion()} is below 8.4.0 (e.g. `PHP_COMPILER_PROFILE=8.2`).
* Withheld on 8.4.0-dev reference profile (matches Zend 8.2 function_exists gate). Enable via
* stable 8.4.0+ or explicit `PHP_COMPILER_PROFILE=8.4` forward profile.
*/
public static function supportsMbTrimFunctions(): bool
{
if (version_compare(self::VERSION, '8.4', '<')) {
return false;
}

if (version_compare(self::VERSION, '8.4.0', '>=')) {
return true;
}

$raw = getenv('PHP_COMPILER_PROFILE');
if (\is_string($raw) && '' !== trim($raw)) {
return version_compare(self::languageProfileVersion(), '8.4.0', '>=');
if (!\is_string($raw) || '' === trim($raw)) {
return false;
}

return version_compare(self::builtinAdvertisementVersion(), '8.4.0', '>=');
return version_compare(self::languageProfileVersion(), '8.4.0', '>=');
}

/**
* mb_trim/ltrim/rtrim visible to function_exists() — same gate as {@see supportsMbTrimFunctions()}.
* mb_trim/ltrim/rtrim visible to function_exists() — stable runtime or forward 8.4+ (#17206).
*/
public static function advertisesMbTrimFunctions(): bool
{
return self::supportsMbTrimFunctions();
if (version_compare(self::VERSION, '8.4.0', '>=')) {
return true;
}

$raw = getenv('PHP_COMPILER_PROFILE');
if (!\is_string($raw) || '' === trim($raw)) {
return false;
}

return version_compare(self::languageProfileVersion(), '8.4.0', '>=');
}

/**
Expand Down Expand Up @@ -1707,29 +1737,81 @@ public static function supportsDisktotalspace(): bool
/**
* PHP 8.3+ crc32c() (ext/standard/crc32.c, issue #3270, #17139).
*
* Enabled by default on the 8.4.0-dev toolchain (runtime reports 8.4; php-src has the builtin since 8.3).
* `PHP_COMPILER_PROFILE=8.2` keeps the Zend 8.2 reference gate (function absent).
* Withheld on 8.4.0-dev reference profile (matches Zend 8.2 function_exists gate). Enable via
* stable 8.4.0+ or explicit `PHP_COMPILER_PROFILE=8.3` / `8.4` forward profile.
*/
public static function supportsCrc32c(): bool
{
if (version_compare(self::VERSION, '8.3', '<')) {
return false;
}

if (version_compare(self::VERSION, '8.4.0', '>=')) {
return true;
}

$raw = getenv('PHP_COMPILER_PROFILE');
if (\is_string($raw) && '' !== trim($raw)) {
return version_compare(self::languageProfileVersion(), '8.3.0', '>=');
if (!\is_string($raw) || '' === trim($raw)) {
return false;
}

return self::advertisesBuiltinSince('8.3.0');
return version_compare(self::languageProfileVersion(), '8.3.0', '>=');
}

/**
* crc32c() visible to function_exists() — same gate as {@see supportsCrc32c()} (#17139).
* crc32c() visible to function_exists() — stable runtime or forward 8.3+ (#17206).
*/
public static function advertisesCrc32c(): bool
{
return self::supportsCrc32c();
if (version_compare(self::VERSION, '8.4.0', '>=')) {
return true;
}

$raw = getenv('PHP_COMPILER_PROFILE');
if (!\is_string($raw) || '' === trim($raw)) {
return false;
}

return version_compare(self::languageProfileVersion(), '8.3.0', '>=');
}

/**
* PHP 8.3+ hebrevc() (ext/standard/string.c, issue #17183, #17206).
*
* Withheld on 8.4.0-dev reference profile (matches Zend 8.2 function_exists gate). Enable via
* stable 8.4.0+ or explicit `PHP_COMPILER_PROFILE=8.3` / `8.4` forward profile.
*/
public static function supportsHebrevc(): bool
{
if (version_compare(self::VERSION, '8.3', '<')) {
return false;
}

if (version_compare(self::VERSION, '8.4.0', '>=')) {
return true;
}

$raw = getenv('PHP_COMPILER_PROFILE');
if (!\is_string($raw) || '' === trim($raw)) {
return false;
}

return version_compare(self::languageProfileVersion(), '8.3.0', '>=');
}

/** hebrevc() visible to function_exists() — stable runtime or forward 8.3+ (#17206). */
public static function advertisesHebrevc(): bool
{
if (version_compare(self::VERSION, '8.4.0', '>=')) {
return true;
}

$raw = getenv('PHP_COMPILER_PROFILE');
if (!\is_string($raw) || '' === trim($raw)) {
return false;
}

return version_compare(self::languageProfileVersion(), '8.3.0', '>=');
}

/**
Expand Down
9 changes: 9 additions & 0 deletions test/compliance/JITTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ public static function providePHPTests(): \Generator
&& !str_contains($name, 'crc32c_phantom')) {
continue;
}
if (!CompilerVersion::supportsHebrevc()
&& str_contains($name, 'hebrevc')
&& !str_contains($name, 'hebrevc_phantom')) {
continue;
}
if (CompilerVersion::supportsHebrevc()
&& str_contains($name, 'hebrevc_phantom')) {
continue;
}
if (!CompilerVersion::supportsMbStrPad()
&& str_contains($name, 'mb_str_pad')
&& !str_contains($name, 'mb_str_pad_phantom')) {
Expand Down
9 changes: 9 additions & 0 deletions test/compliance/VMTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,15 @@ public static function providePHPTests(): \Generator
&& !str_contains($name, 'crc32c_phantom')) {
continue;
}
if (!CompilerVersion::supportsHebrevc()
&& str_contains($name, 'hebrevc')
&& !str_contains($name, 'hebrevc_phantom')) {
continue;
}
if (CompilerVersion::supportsHebrevc()
&& str_contains($name, 'hebrevc_phantom')) {
continue;
}
if (!CompilerVersion::supportsJsonValidate()
&& str_contains($name, 'json_validate')
&& !str_contains($name, 'json_validate_phantom')
Expand Down
2 changes: 2 additions & 0 deletions test/compliance/cases/stdlib/hebrevc.phpt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
--TEST--
stdlib hebrevc() visual Hebrew with newline conversion (#17183)
--ENV--
PHP_COMPILER_PROFILE=8.4
--FILE--
<?php
$shalomOlam = "\xf9\xec\xe5\xed\x20\xf2\xe5\xec\xed";
Expand Down
2 changes: 2 additions & 0 deletions test/compliance/cases/stdlib/hebrevc_jit.phpt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
--TEST--
stdlib hebrevc() JIT (#17183)
--ENV--
PHP_COMPILER_PROFILE=8.4
--JIT--
--FILE--
<?php
Expand Down
9 changes: 9 additions & 0 deletions test/compliance/cases/stdlib/hebrevc_phantom.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
--TEST--
stdlib hebrevc() — not advertised on PHP 8.2 reference profile (#17206, ext/standard/string.c)
--ENV--
PHP_COMPILER_PROFILE=8.2
--FILE--
<?php
echo function_exists('hebrevc') ? "fail\n" : "ok\n";
--EXPECT--
ok
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
stdlib forward-profile builtins — withheld on 8.2 reference profile (#17206)
--FILE--
<?php
$leaked = array_filter(
['mb_trim', 'crc32c', 'hebrevc', 'attribute_exists', 'class_uses_recursive'],
static fn (string $fn): bool => function_exists($fn)
);
echo [] === $leaked ? "ok\n" : 'fail: '.implode(',', $leaked)."\n";
--EXPECT--
ok
4 changes: 3 additions & 1 deletion test/repro/maintainer_gap_crc32c_builtin.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
declare(strict_types=1);

/**
* Maintainer repro: crc32c() enabled on default dev profile (#17139, ext/standard/crc32.c).
* Maintainer repro: crc32c() on forward profile (#17139, ext/standard/crc32.c).
*
* Run with: PHP_COMPILER_PROFILE=8.4 php bin/vm.php test/repro/maintainer_gap_crc32c_builtin.php
*/

if (!function_exists('crc32c')) {
Expand Down
29 changes: 29 additions & 0 deletions test/repro/maintainer_gap_forward_profile_builtin_leak_82.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

/**
* Maintainer repro: forward-profile builtins must not leak on 8.2 reference profile (#17206).
*
* Default harness (unset PHP_COMPILER_PROFILE) matches Zend 8.2 function_exists gates.
*/

$leaked = [];
foreach ([
'mb_trim',
'crc32c',
'hebrevc',
'attribute_exists',
'class_uses_recursive',
] as $fn) {
if (function_exists($fn)) {
$leaked[] = $fn;
}
}

if ([] !== $leaked) {
fwrite(STDERR, 'fail: leaked on reference profile: '.implode(', ', $leaked)."\n");
exit(1);
}

echo "ok\n";
2 changes: 2 additions & 0 deletions test/repro/maintainer_gap_hebrevc_missing.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

/**
* Maintainer repro: hebrevc() registration and newline conversion (#17183).
*
* Run with: PHP_COMPILER_PROFILE=8.4 php bin/vm.php test/repro/maintainer_gap_hebrevc_missing.php
*/

if (!function_exists('hebrevc')) {
Expand Down
Loading