diff --git a/docs/bootstrap-inventory.md b/docs/bootstrap-inventory.md index cd87308f08..6e124816e9 100644 --- a/docs/bootstrap-inventory.md +++ b/docs/bootstrap-inventory.md @@ -8,11 +8,11 @@ Regenerate: `php script/bootstrap-inventory.php` | Metric | Count | |--------|------:| -| PHP files on vm.php path | 6561 | -| Phase A inventory files (M2 ratio SSOT) | 6561 | +| PHP files on vm.php path | 6562 | +| Phase A inventory files (M2 ratio SSOT) | 6562 | | Phase A ratio-deferred paths | 0 | | Source constructs flagged (blockers) | 0 | -| Source constructs flagged (warnings) | 21094 | +| Source constructs flagged (warnings) | 21100 | ## Compiler CFG gaps (`lib/Compiler.php`) @@ -1859,6 +1859,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag | `ext/soap/SoapFaultConstruct.php` | 0 | 1 | | `ext/soap/VmSoapClient.php` | 0 | 60 | | `ext/soap/VmSoapEncoding.php` | 0 | 32 | +| `ext/soap/VmSoapOpaque.php` | 0 | 6 | | `ext/soap/VmSoapServer.php` | 0 | 47 | | `ext/soap/bootstrap_soapfault.php` | 0 | 1 | | `ext/soap/is_soap_fault.php` | 0 | 2 | @@ -21588,14 +21589,14 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag ### `ext/soap/BuiltinClasses.php` **Warnings** (review for bootstrap subset): -- new Variable (line 47) -- new Variable (line 48) - new Variable (line 49) -- new ClassProperty (line 57) -- new ClassProperty (line 60) -- new ClassProperty (line 63) -- new ClassProperty (line 66) -- new SoapFaultConstruct (line 69) +- new Variable (line 50) +- new Variable (line 51) +- new ClassProperty (line 59) +- new ClassProperty (line 62) +- new ClassProperty (line 65) +- new ClassProperty (line 68) +- new SoapFaultConstruct (line 71) - 2 class method(s) ### `ext/soap/Module.php` @@ -21618,7 +21619,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag ### `ext/soap/SoapExtensionPolicy.php` **Warnings** (review for bootstrap subset): -- 8 class method(s) +- 9 class method(s) ### `ext/soap/SoapFaultConstruct.php` @@ -21725,6 +21726,16 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag - new ArgumentCountError (line 220) - 10 class method(s) +### `ext/soap/VmSoapOpaque.php` + +**Warnings** (review for bootstrap subset): +- new ClassEntry (line 46) +- new ObjectEntry (line 60) +- new ObjectEntry (line 74) +- new Variable (line 82) +- new Variable (line 90) +- 6 class method(s) + ### `ext/soap/VmSoapServer.php` **Warnings** (review for bootstrap subset): @@ -52709,7 +52720,7 @@ Rank live CFG gaps across inventory files: `php script/bootstrap-inventory-triag ### `lib/VM/ReservedBuiltinClass.php` **Warnings** (review for bootstrap subset): -- new Error (line 47) +- new Error (line 50) - 4 class method(s) ### `lib/VM/ResourceSupport.php` diff --git a/docs/capabilities.md b/docs/capabilities.md index 735a336526..6dd2f7e901 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -1200,7 +1200,7 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand. | `str_starts_with` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | | `str_word_count` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | | `strcasecmp` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | -| `strchr` | yes | yes | yes | standard | | +| `strchr` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | | `strcmp` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | | `strcoll` | yes | yes | yes | standard | JIT PHPT | | `strcspn` | yes | yes | yes | standard | empty $characters: PHP 8.4 full byte length (GH-12592, #7088); JIT PHPT; AOT PHPT | diff --git a/docs/pages/capability-comparison.html b/docs/pages/capability-comparison.html index 28b79a9310..ab4cffd531 100644 --- a/docs/pages/capability-comparison.html +++ b/docs/pages/capability-comparison.html @@ -52,7 +52,7 @@
capabilities-syntax.md
and capabilities.md.
- Generated 2026-07-25 (matrix mtime).
+ Generated 2026-07-26 (matrix mtime).
diff --git a/ext/soap/BuiltinClasses.php b/ext/soap/BuiltinClasses.php
index 9c1056f4d7..864e0ce14b 100644
--- a/ext/soap/BuiltinClasses.php
+++ b/ext/soap/BuiltinClasses.php
@@ -23,6 +23,8 @@ public static function register(Context $ctx): void
VmSoapEncoding::register($ctx);
VmSoapServer::registerClass($ctx);
VmSoapClient::registerClass($ctx);
+ // PHP 8.4+ Soap\Url / Soap\Sdl opaque types (#23230).
+ VmSoapOpaque::register($ctx);
foreach (\array_diff(\array_keys($ctx->classes), $before) as $lc) {
$ctx->classes[$lc]->isInternal = true;
}
diff --git a/ext/soap/SoapExtensionPolicy.php b/ext/soap/SoapExtensionPolicy.php
index 46125a4540..2e6ae1f223 100644
--- a/ext/soap/SoapExtensionPolicy.php
+++ b/ext/soap/SoapExtensionPolicy.php
@@ -36,6 +36,24 @@ public static function advertisesExceptionClass(): bool
return self::advertisesExtension();
}
+ /**
+ * Soap\Url / Soap\Sdl — php-src 8.4+ only (soap.stub.php resource→object; #23230).
+ *
+ * SoapClient may be advertised via host php-soap on 8.2; these types stay withheld until
+ * the effective language profile (or host PHP) is ≥ 8.4.
+ */
+ public static function advertisesOpaqueUrlSdlTypes(): bool
+ {
+ if (!self::advertisesExtension()) {
+ return false;
+ }
+ if (\version_compare(\PHP_VERSION, '8.4.0', '>=')) {
+ return true;
+ }
+
+ return \version_compare(\PHPCompiler\CompilerVersion::languageProfileVersion(), '8.4.0', '>=');
+ }
+
/** Compliance filenames that exercise SoapClient / SoapServer / SoapFault. */
public static function isSoapComplianceCase(string $testFileName): bool
{
diff --git a/ext/soap/VmSoapOpaque.php b/ext/soap/VmSoapOpaque.php
new file mode 100644
index 0000000000..0c6416c42f
--- /dev/null
+++ b/ext/soap/VmSoapOpaque.php
@@ -0,0 +1,95 @@
+classes[$lc])) {
+ $ctx->classes[$lc]->isInternal = true;
+ $ctx->classes[$lc]->isFinal = true;
+
+ return;
+ }
+
+ $entry = new ClassEntry($name);
+ $entry->isInternal = true;
+ $entry->isFinal = true;
+ $ctx->classes[$lc] = $entry;
+ }
+
+ /** Factory for SoapClient::$httpurl / related wiring (php-src soap_url_object_create). */
+ public static function newUrlObject(Context $ctx): ObjectEntry
+ {
+ self::register($ctx);
+ $class = $ctx->classes[self::URL_CLASS_LC] ?? null;
+ if (null === $class) {
+ throw new \LogicException('Soap\\Url is not registered in this compiler build');
+ }
+ $object = new ObjectEntry($class);
+ $object->constructed = true;
+
+ return $object;
+ }
+
+ /** Factory for SoapClient::$sdl (php-src soap_sdl_object_create). */
+ public static function newSdlObject(Context $ctx): ObjectEntry
+ {
+ self::register($ctx);
+ $class = $ctx->classes[self::SDL_CLASS_LC] ?? null;
+ if (null === $class) {
+ throw new \LogicException('Soap\\Sdl is not registered in this compiler build');
+ }
+ $object = new ObjectEntry($class);
+ $object->constructed = true;
+
+ return $object;
+ }
+
+ public static function urlVariable(Context $ctx): Variable
+ {
+ $var = new Variable(Variable::TYPE_OBJECT);
+ $var->object(self::newUrlObject($ctx));
+
+ return $var;
+ }
+
+ public static function sdlVariable(Context $ctx): Variable
+ {
+ $var = new Variable(Variable::TYPE_OBJECT);
+ $var->object(self::newSdlObject($ctx));
+
+ return $var;
+ }
+}
diff --git a/lib/VM/ReservedBuiltinClass.php b/lib/VM/ReservedBuiltinClass.php
index 9312c2230c..00af8f49c1 100644
--- a/lib/VM/ReservedBuiltinClass.php
+++ b/lib/VM/ReservedBuiltinClass.php
@@ -25,6 +25,9 @@ final class ReservedBuiltinClass
'pgsql\\connection' => 'Cannot directly construct PgSql\Connection, use pg_connect() or pg_pconnect() instead',
'pgsql\\result' => 'Cannot directly construct PgSql\Result, use a dedicated function instead',
'pgsql\\lob' => 'Cannot directly construct PgSql\Lob, use pg_lo_open() instead',
+ // php-src ext/soap/soap.c soap_url/sdl_object_get_constructor (#23230)
+ 'soap\\url' => 'Cannot directly construct Soap\\Url',
+ 'soap\\sdl' => 'Cannot directly construct Soap\\Sdl',
];
/** @var array