Plugins: Store result of call to array_keys, to save repeated calls in WP_Hook class.

In the `WP_Hook` class the function `array_keys` was called every time an array of hook priorities was needed. For sites with lots of filters or actions, this would result in thousands of calls to the `array_keys` function, which uses server resources. Instead of recomputing this array every time it is needed, only compute it when filters are added and removed, then store the result as a class property. Improve unit tests to ensure this behaviour is tested. 

Props spacedmonkey, bor0, flixos90, hellofromTonya, mukesh27.
Fixes #58458.
Built from https://develop.svn.wordpress.org/trunk@56609


git-svn-id: http://core.svn.wordpress.org/trunk@56121 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
spacedmonkey 2023-09-18 12:41:18 +00:00
parent cc1bb87546
commit 323d8cb19d
2 changed files with 22 additions and 5 deletions

View File

@ -26,6 +26,14 @@ final class WP_Hook implements Iterator, ArrayAccess {
*/
public $callbacks = array();
/**
* Priorities list.
*
* @since 6.4.0
* @var array
*/
protected $priorities = array();
/**
* The priority keys of actively running iterations of a hook.
*
@ -86,6 +94,8 @@ final class WP_Hook implements Iterator, ArrayAccess {
ksort( $this->callbacks, SORT_NUMERIC );
}
$this->priorities = array_keys( $this->callbacks );
if ( $this->nesting_level > 0 ) {
$this->resort_active_iterations( $priority, $priority_existed );
}
@ -102,7 +112,7 @@ final class WP_Hook implements Iterator, ArrayAccess {
* filter was added. Default false.
*/
private function resort_active_iterations( $new_priority = false, $priority_existed = false ) {
$new_priorities = array_keys( $this->callbacks );
$new_priorities = $this->priorities;
// If there are no remaining hooks, clear out all running iterations.
if ( ! $new_priorities ) {
@ -187,6 +197,8 @@ final class WP_Hook implements Iterator, ArrayAccess {
if ( ! $this->callbacks[ $priority ] ) {
unset( $this->callbacks[ $priority ] );
$this->priorities = array_keys( $this->callbacks );
if ( $this->nesting_level > 0 ) {
$this->resort_active_iterations();
}
@ -262,9 +274,11 @@ final class WP_Hook implements Iterator, ArrayAccess {
}
if ( false === $priority ) {
$this->callbacks = array();
$this->callbacks = array();
$this->priorities = array();
} elseif ( isset( $this->callbacks[ $priority ] ) ) {
unset( $this->callbacks[ $priority ] );
$this->priorities = array_keys( $this->callbacks );
}
if ( $this->nesting_level > 0 ) {
@ -289,7 +303,7 @@ final class WP_Hook implements Iterator, ArrayAccess {
$nesting_level = $this->nesting_level++;
$this->iterations[ $nesting_level ] = array_keys( $this->callbacks );
$this->iterations[ $nesting_level ] = $this->priorities;
$num_args = count( $args );
@ -348,7 +362,7 @@ final class WP_Hook implements Iterator, ArrayAccess {
*/
public function do_all_hook( &$args ) {
$nesting_level = $this->nesting_level++;
$this->iterations[ $nesting_level ] = array_keys( $this->callbacks );
$this->iterations[ $nesting_level ] = $this->priorities;
do {
$priority = current( $this->iterations[ $nesting_level ] );
@ -481,6 +495,8 @@ final class WP_Hook implements Iterator, ArrayAccess {
} else {
$this->callbacks[ $offset ] = $value;
}
$this->priorities = array_keys( $this->callbacks );
}
/**
@ -495,6 +511,7 @@ final class WP_Hook implements Iterator, ArrayAccess {
#[ReturnTypeWillChange]
public function offsetUnset( $offset ) {
unset( $this->callbacks[ $offset ] );
$this->priorities = array_keys( $this->callbacks );
}
/**

View File

@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '6.4-alpha-56608';
$wp_version = '6.4-alpha-56609';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.