Make WordPress Core

Changeset 62408 for trunk


Ignore:
Timestamp:
05/22/2026 06:59:15 AM (4 months ago)
Author:
westonruter
Message:

Plugins: Improve hook performance by using spl_object_id() instead of spl_object_hash() to construct unique IDs.

  • Also use spl_object_id() similarly when registering and unregistering classic widgets.
  • Improve typing and phpdoc in _wp_filter_build_unique_id(). Return null for malformed callbacks.
  • Add tests for _wp_filter_build_unique_id().
  • Improve type safety of WP_Hook::add_filter() in case an invalid callback is provided for parity with ::has_filter() and ::remove_filter().

Developed in https://github.com/WordPress/wordpress-develop/pull/11865
Follow-up to r46220, r46801, r60179.

Props bor0, westonruter, SergeyBiryukov, schlessera, arshidkv12, knutsp, spacedmonkey, swissspidy.
See #64898.
Fixes #58291.

Location:
trunk
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-hook.php

    r61457 r62408  
    8686
    8787                $idx = _wp_filter_build_unique_id( $hook_name, $callback, $priority );
     88                if ( null === $idx ) {
     89                        return;
     90                }
    8891
    8992                $priority_existed = isset( $this->callbacks[ $priority ] );
  • trunk/src/wp-includes/class-wp-widget-factory.php

    r54133 r62408  
    5858        public function register( $widget ) {
    5959                if ( $widget instanceof WP_Widget ) {
    60                         $this->widgets[ spl_object_hash( $widget ) ] = $widget;
     60                        $this->widgets[ spl_object_id( $widget ) ] = $widget;
    6161                } else {
    6262                        $this->widgets[ $widget ] = new $widget();
     
    7575        public function unregister( $widget ) {
    7676                if ( $widget instanceof WP_Widget ) {
    77                         unset( $this->widgets[ spl_object_hash( $widget ) ] );
     77                        unset( $this->widgets[ spl_object_id( $widget ) ] );
    7878                } else {
    7979                        unset( $this->widgets[ $widget ] );
  • trunk/src/wp-includes/plugin.php

    r62397 r62408  
    987987 * @since 5.3.0 Removed workarounds for spl_object_hash().
    988988 *              `$hook_name` and `$priority` are no longer used,
    989  *              and the function always returns a string.
     989 *              and no longer returns false, but can still return void for invalid callbacks.
     990 * @since 6.9.0 Returns explicit null if an invalid callback is supplied.
     991 * @since 7.1.0 Uses spl_object_id() instead of spl_object_hash() for performance.
    990992 *
    991993 * @access private
    992994 *
    993  * @param string                $hook_name Unused. The name of the filter to build ID for.
    994  * @param callable|string|array $callback  The callback to generate ID for. The callback may
    995  *                                         or may not exist.
    996  * @param int                   $priority  Unused. The order in which the functions
    997  *                                         associated with a particular action are executed.
    998  * @return string|null Unique function ID for usage as array key.
    999  *                     Null if a valid `$callback` is not passed.
    1000  */
    1001 function _wp_filter_build_unique_id( $hook_name, $callback, $priority ) {
     995 * @param string   $hook_name Unused. The name of the filter to build ID for.
     996 * @param callable $callback  The callback to generate ID for. The callback may
     997 *                            or may not exist.
     998 * @param int      $priority  Unused. The order in which the functions
     999 *                            associated with a particular action are executed.
     1000 * @return string|null Unique function ID for usage as array key, or null if it couldn't be determined.
     1001 */
     1002function _wp_filter_build_unique_id( $hook_name, $callback, $priority ): ?string {
    10021003        if ( is_string( $callback ) ) {
    10031004                return $callback;
     
    10051006
    10061007        if ( is_object( $callback ) ) {
    1007                 // Closures are currently implemented as objects.
    1008                 $callback = array( $callback, '' );
    1009         } else {
    1010                 $callback = (array) $callback;
     1008                return (string) spl_object_id( (object) $callback );
     1009        }
     1010
     1011        $callback = (array) $callback;
     1012        if ( ! isset( $callback[1] ) || ! is_string( $callback[1] ) ) {
     1013                return null;
    10111014        }
    10121015
    10131016        if ( is_object( $callback[0] ) ) {
    10141017                // Object class calling.
    1015                 return spl_object_hash( $callback[0] ) . $callback[1];
     1018                return ( (string) spl_object_id( $callback[0] ) ) . $callback[1];
    10161019        } elseif ( is_string( $callback[0] ) ) {
    10171020                // Static calling.
Note: See TracChangeset for help on using the changeset viewer.