PHP 8.5 adoption
Added to test suite in xp-framework/core@009498040
Changes in PHP 8.5
See https://wiki.php.net/rfc#php_85
Initial results
See https://github.com/xp-framework/core/actions/runs/14570004500/job/40865400220:
- [x] realpath(): Argument 1 ($path) must not contain any null bytes)
- [x] Handling of
selfandparent
Handling of self and parent
$r= new ReflectionClass(new class() {
public function instance(): self { return $this; }
});
$type= $r->getMethod('instance')->getReturnType();
var_dump($type->getName()); // PHP 8.4: "self", PHP 8.5: "class@anonymous"
The problem is not per se that the name is resolved by PHP, the problem is that "class@anonymous" is not the full name of the class, which is more like "class@anonymous\000Command line code:1$0". The NUL character in the string truncates the name in PHP 8.5, leading the problems when trying to create ReflectionClass instances from the type name!
See https://github.com/php/php-src/issues/18373
Extended example
...showing an abbreviated version of how the XP reflection API works:
<?php
class ReflectionPrimitive {
public string $name;
public function __construct(ReflectionNamedType $type) {
$this->name= $type->getName();
}
}
$reflect= new ReflectionClass(new class() {
public function name(): string { return 'Test'; }
public function date(): DateTime { return new DateTime(); }
public function with(): self { return $this; }
});
foreach (['name', 'date', 'with'] as $method) {
echo "== {$method} ==\n";
$type= $reflect->getMethod($method)->getReturnType();
var_dump($type->getName());
// Shortened for brevity: Handling of union and intersecton types
if ($type->isBuiltin()) {
$return= new ReflectionPrimitive($type);
} else {
$return= match ($type->getName()) {
'self' => $reflect,
'static' => $reflect,
'parent' => $reflect->getParentClass(),
default => new ReflectionClass($type->getName())
};
}
var_dump($return);
}
PHP 8.4 output:
== name ==
string(6) "string"
object(ReflectionPrimitive)#2 (1) {
["name"]=>
string(6) "string"
}
== date ==
string(8) "DateTime"
object(ReflectionClass)#3 (1) {
["name"]=>
string(8) "DateTime"
}
== with ==
string(4) "self"
object(ReflectionClass)#1 (1) {
["name"]=>
string(73) "class@anonymousC:\Tools\Cygwin\home\timmf\devel\xp\core\reflect.php:10$0"
}
PHP 8.5 output:
== name ==
string(6) "string"
object(ReflectionPrimitive)#2 (1) {
["name"]=>
string(6) "string"
}
== date ==
string(8) "DateTime"
object(ReflectionClass)#3 (1) {
["name"]=>
string(8) "DateTime"
}
== with ==
string(15) "class@anonymous"
Fatal error: Uncaught ReflectionException: Class "class@anonymous" does not exist in C:\Tools\Cygwin\home\timmf\devel\xp\core\reflect.php:30
Stack trace:
#0 C:\Tools\Cygwin\home\timmf\devel\xp\core\reflect.php(30): ReflectionClass->__construct('class@anonymous')
#1 {main}
thrown in C:\Tools\Cygwin\home\timmf\devel\xp\core\reflect.php on line 30
the problem is that "class@anonymous" is not the full name of the class
This issue might have already been fixed in PHP in the meantime, see https://github.com/php/php-src/issues/18373#issuecomment-2818059577
However, the names being resolved still needs a minor patch to work:
diff --git a/src/main/php/lang/Type.class.php b/src/main/php/lang/Type.class.php
index e8fd37486..dff5d0b52 100755
--- a/src/main/php/lang/Type.class.php
+++ b/src/main/php/lang/Type.class.php
@@ -287,7 +287,7 @@ class Type implements Value {
// card type.
// * Anything else is a qualified or unqualified class name
$l= strlen($name);
- $p= strcspn($name, '<&|[*(');
+ $p= strcspn($name, '<&|[*(@');
if ($p === $l) {
return isset($context[$name]) ? $context[$name]() : ((isset($context['*']) && strcspn($name, '.\\') === $l)
? $context['*']($name)
@@ -334,6 +334,8 @@ class Type implements Value {
} else {
$t= self::named($base, $context)->newGenericType($components);
}
+ } else if ('@' === $name[$p]) {
+ return new XPClass($name);
} else {
$t= self::named(trim(substr($name, 0, $p)), $context);
$name= substr($name, $p);
With this patch, there is a handful of tests that actually test for self and parent failing, see https://github.com/xp-framework/core/actions/runs/14571525578/job/40869557458. We will need to rewrite them to handle this.
Now only PHP 8.5 on Windows is failing, see https://github.com/xp-framework/core/actions/runs/14572384660, a newer build might fix this, see https://github.com/php/php-src/issues/18373#issuecomment-2818059577
Fix for Non-canonical cast (double) is deprecated, use the (float) cast instead (see here):
- [x] https://github.com/xp-forge/json/releases/tag/v6.0.1
- [x] https://github.com/xp-framework/ftp/releases/tag/v12.0.0
- [x] https://github.com/xp-framework/rdbms/releases/tag/v13.4.0
- [x] https://github.com/xp-forge/json-patch/releases/tag/v2.1.1
Another small change to chr(), see here:
⨯ util.unittest.BytesTest::byteArrayToBytes
Succeeded but raised 1 warning(s)
at <main>::@error() [line 27 of Bytes.class.php] E_DEPRECATED: chr(): Providing a value not in-between 0 and 255 is deprecated, this is because a byte value must be in the [0, 255] interval. The value used will be constrained using % 256
at test.execution.TestCase::run() [line 32 of RunTest.class.php]
at test.execution.RunTest::run() [line 116 of Runner.class.php]
at xp.test.Runner::main() [line 389 of class-main.php]
Released https://github.com/xp-framework/core/releases/tag/v12.6.1 w/ fixes for https://wiki.php.net/rfc/deprecations_php_8_5
The Ignore annotation on the lang.unittest.TypeUnionTest::php8_native_union_with_self test can be removed once the Windows PHP builds on GitHub actions are up-to-date again now that php/php-src@6497c6c455ef0cb2debe1891d6c6d00ece95a3c2 has been committed.
E_DEPRECATED: Using null as an array offset is deprecated, use an empty string instead
- [x] line 16 of TypeDefinition.class.php
- [x] line 31 of TypeDefinition.class.php
- [x] line 48 of DynamicClassLoader.class.php
- [x] line 103of DynamicClassLoader.class.php
- [x] line 127 of Properties.class.php
- [x] line 256 of Properties.class.php
- [x] line 118 of Properties.class.php
- [x] line 119 of Properties.class.php
- [x] line 122 of Properties.class.php
- [x] line 124 of Properties.class.php
- [x] line 127 of Properties.class.php
- [x] line 236 of Properties.class.php
- [x] line 272 of Properties.class.php
- [x] line 296 of Properties.class.php
See https://github.com/xp-framework/core/actions/runs/17506126128/job/49729895116 (before 💣) See https://github.com/xp-framework/core/actions/runs/17506360976/job/49730568189 (after ✅)
E_DEPRECATED: Implicit conversion from float (...) to int loses precision
- [x] line 157 of UUID.class.php
- [x] line 158 of UUID.class.php
- [x] line 159 of UUID.class.php
Update: These were caused by me using the x86 binary, reverted the changes
Smaller adjustments were also necessary for the XP Compiler to fix Arrow functions on the right hand side of |> must be parenthesized errors:
- return "test" |> fn($x) => $x.": OK";
+ return "test" |> (fn($x) => $x.": OK");
See https://externals.io/message/128473#128554
Released https://github.com/xp-framework/core/releases/tag/v12.6.2