Make WordPress Core

Changes between Initial Version and Version 3 of Ticket #65919


Ignore:
Timestamp:
08/20/2026 04:40:50 PM (2 months ago)
Author:
westonruter
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Ticket #65919

    • Property Owner set to westonruter
    • Property Status new → accepted
  • Ticket #65919 – Description

    initial v3  
    77}}}
    88
    9 The function return value is a correct `string`. However, the value is then
    10 used as an array key in `WP_Hook::add_filter()`:
     9The function return value is a correct `string`. However, the value is then used as an array key in `WP_Hook::add_filter()`:
    1110
    1211{{{#!php
    … …  
    1413}}}
    1514
    16 For a bare object, `$idx` is a canonical decimal string (`"5292"`), so PHP
    17 coerces it back to `int` on assignment. The `(string)` cast therefore does not
    18 achieve key-type consistency — it is nullified one layer down, at the point of
    19 storage.
     15For a bare object, `$idx` is a canonical decimal string (`"5292"`), so PHP coerces it back to `int` on assignment. The `(string)` cast therefore does not achieve key-type consistency — it is nullified one layer down, at the point of storage.
    2016
    21 This affects bare-object callbacks only. `[ $obj, 'method' ]` yields
    22 `"5292method"`, and `Class::method` / function-name callbacks remain strings.
     17This affects bare-object callbacks only. `[ $obj, 'method' ]` yields `"5292method"`, and `Class::method` / function-name callbacks remain strings.
    2318
    2419== Why the existing tests did not catch it ==
    25 The unit tests added in [62408] assert the **return type of the function**
    26 (string), object uniqueness, stability, and null for malformed input. They do
    27 not assert the **type of the resulting array key** in `WP_Hook::$callbacks`,
    28 which is where the coercion happens. A regression test should read back
    29 `array_keys( $wp_filter[ $hook ]->callbacks[ $priority ] )` and assert the key
    30 is a string.
     20The unit tests added in [62408] assert the **return type of the function** (string), object uniqueness, stability, and null for malformed input. They do not assert the **type of the resulting array key** in `WP_Hook::$callbacks`, which is where the coercion happens. A regression test should read back `array_keys( $wp_filter[ $hook ]->callbacks[ $priority ] )` and assert the key is a string.
    3121
    3222== Steps to reproduce ==
    … …  
    4838}}}
    4939
    50 (`spl_object_id()` values are not deterministic across runs; the numbers above
    51 are illustrative.)
     40(`spl_object_id()` values are not deterministic across runs; the numbers above are illustrative.)
    5241
    5342== Impact ==
    54 `WP_Hook::$callbacks` is a public property introspected by caching, profiling,
    55 and debugging plugins. Any consumer under `strict_types`, or passing the key to
    56 a `string`-typed parameter, now fatals. Confirmed in the wild: WP Rocket
    57 (`Cloudflare.php`, `substr()` on the key) broke immediately on 7.1.
     43`WP_Hook::$callbacks` is a public property introspected by caching, profiling, and debugging plugins. Any consumer under `strict_types`, or passing the key to a `string`-typed parameter, now fatals. Confirmed in the wild: WP Rocket (`Cloudflare.php`, `substr()` on the key) broke immediately on 7.1.
    5844
    5945== Possible resolutions ==
    60 1. Normalize the object branch to a non-numeric string (e.g. a short constant
    61    prefix) so the key can never be coerced. This makes the existing `(string)`
    62    cast actually effective. Trade-off: reintroduces a concat/allocation that
    63    [62408] removed from the hot path.
    64 2. Cast keys to string at the `WP_Hook` read/iteration boundaries.
    65 3. Accept int keys as intended, document it on `@return` and on
    66    `WP_Hook::$callbacks`, and treat consumers as responsible.
    67 
    68 In all cases, add a regression test asserting the **stored key type**, not just
    69 the function return type.
    70 
    71 Introduced in [62408]. Related: #64898.
     461. Normalize the object