ms. * * @var array */ private $ms = array(); /** * Between muplugins_loaded and the first regular plugin. * * @var bool */ private $between = false; /** * Constructor. * * @param Owner $owner Owner resolver. */ public function __construct( Owner $owner ) { $this->owner = $owner; } /** * Start (call before plugins are included). */ public function start(): void { $this->last = (float) hrtime( true ); add_action( 'plugin_loaded', array( $this, 'on_plugin_loaded' ), -PHP_INT_MAX ); add_action( 'mu_plugin_loaded', array( $this, 'on_plugin_loaded' ), -PHP_INT_MAX ); add_action( 'muplugins_loaded', array( $this, 'restart' ), PHP_INT_MAX ); add_filter( 'pre_option_active_plugins', array( $this, 'restart_on_read' ), PHP_INT_MAX ); add_filter( 'option_active_plugins', array( $this, 'restart_on_read' ), PHP_INT_MAX ); add_action( 'plugins_loaded', array( $this, 'stop' ), -PHP_INT_MAX ); } /** * Must-use plugins are done: restart the clock so network-activated plugins and the * muplugins_loaded callbacks are not charged to the first regular plugin. */ public function restart(): void { $this->between = true; $this->last = (float) hrtime( true ); } /** * The active plugins list is read right before regular plugins load: restart the clock again so * the core setup in between is not charged either. Returns the value unchanged. * * @param mixed $value Option value (or pre_option short-circuit value). * @return mixed */ public function restart_on_read( $value ) { if ( $this->between ) { $this->last = (float) hrtime( true ); } return $value; } /** * A plugin main file finished including. * * @param string $file Plugin file. */ public function on_plugin_loaded( $file ): void { $this->between = false; $now = (float) hrtime( true ); $delta = ( $now - $this->last ) / 1e6; $this->last = $now; $key = $this->owner->for_file( (string) $file ); if ( $this->owner->is_self( $key ) ) { return; } $this->ms[ $key ] = ( $this->ms[ $key ] ?? 0.0 ) + $delta; } /** * Stop listening. */ public function stop(): void { $this->between = false; remove_action( 'plugin_loaded', array( $this, 'on_plugin_loaded' ), -PHP_INT_MAX ); remove_action( 'mu_plugin_loaded', array( $this, 'on_plugin_loaded' ), -PHP_INT_MAX ); remove_action( 'muplugins_loaded', array( $this, 'restart' ), PHP_INT_MAX ); remove_filter( 'pre_option_active_plugins', array( $this, 'restart_on_read' ), PHP_INT_MAX ); remove_filter( 'option_active_plugins', array( $this, 'restart_on_read' ), PHP_INT_MAX ); } /** * Owner => include ms. * * @return array */ public function results(): array { $out = array(); foreach ( $this->ms as $k => $v ) { $out[ $k ] = round( $v, 3 ); } return $out; } /** * Record a manual measurement (tests / synthetic). * * @param string $owner_key Owner. * @param float $ms Milliseconds. */ public function add( string $owner_key, float $ms ): void { $this->ms[ $owner_key ] = ( $this->ms[ $owner_key ] ?? 0.0 ) + $ms; } }