diff options
author | daniel <dkinzler@wikimedia.org> | 2022-10-25 16:03:05 +0200 |
---|---|---|
committer | daniel <dkinzler@wikimedia.org> | 2023-03-09 10:20:44 +0100 |
commit | db729e46f6da1381ed36aa965fd768ed22809cba (patch) | |
tree | 745270ec6df1399413d6c49ac5d5eda2032d3a25 /includes/HookContainer | |
parent | d19f30cedeb94a0a711f8e440df3c21992b8217d (diff) | |
download | mediawikicore-db729e46f6da1381ed36aa965fd768ed22809cba.tar.gz mediawikicore-db729e46f6da1381ed36aa965fd768ed22809cba.zip |
Treat $wgHooks as a regular setting
$wgHooks should be treated like a regular setting, which cannot be
manipulated after bootstrapping is complete. This will allow us to
greatly simplify the logic in HookContainer.
Replacing $wgHooks with a fake array after bootstrapping allows us to
detect any remaining live access to $wgHooks without breaking
functionality.
The plan is to have the fake array emit deprecation warnings in the 1.40
release, and make it throw exceptions in later releases.
See Iddcb760cf8961316d6527e81b9aa968657d8354c for the deprecation
warnings.
Bug: T331602
Change-Id: I0ebba9a29f81b0d86ad8fd84d478fb244f9e9c15
Diffstat (limited to 'includes/HookContainer')
-rw-r--r-- | includes/HookContainer/FauxGlobalHookArray.php | 77 | ||||
-rw-r--r-- | includes/HookContainer/FauxHookHandlerArray.php | 89 | ||||
-rw-r--r-- | includes/HookContainer/GlobalHookRegistry.php | 37 | ||||
-rw-r--r-- | includes/HookContainer/HookContainer.php | 9 |
4 files changed, 171 insertions, 41 deletions
diff --git a/includes/HookContainer/FauxGlobalHookArray.php b/includes/HookContainer/FauxGlobalHookArray.php new file mode 100644 index 000000000000..d01883e37dc7 --- /dev/null +++ b/includes/HookContainer/FauxGlobalHookArray.php @@ -0,0 +1,77 @@ +<?php + +namespace MediaWiki\HookContainer; + +use InvalidArgumentException; + +/** + * @internal + */ +class FauxGlobalHookArray implements \ArrayAccess { + + private HookContainer $hookContainer; + + /** + * The original handler array. + * @var array + */ + private array $originalArray; + + /** + * @param HookContainer $hookContainer + * @param array $originalArray + */ + public function __construct( HookContainer $hookContainer, array $originalArray = [] ) { + $this->hookContainer = $hookContainer; + $this->originalArray = $originalArray; + } + + /** + * @inheritDoc + */ + #[\ReturnTypeWillChange] + public function offsetExists( $key ) { + return $this->hookContainer->isRegistered( $key ); + } + + /** + * @inheritDoc + */ + #[\ReturnTypeWillChange] + public function offsetGet( $key ) { + return new FauxHookHandlerArray( $this->hookContainer, $key ); + } + + /** + * @inheritDoc + */ + #[\ReturnTypeWillChange] + public function offsetSet( $key, $value ) { + if ( !is_string( $key ) ) { + throw new InvalidArgumentException( '$key must be a string' ); + } + if ( !is_array( $value ) ) { + throw new InvalidArgumentException( '$value must be an array' ); + } + + $this->hookContainer->clear( $key ); + + foreach ( $value as $handler ) { + $this->hookContainer->register( $key, $handler ); + } + } + + /** + * @inheritDoc + */ + #[\ReturnTypeWillChange] + public function offsetUnset( $key ) { + if ( $this->hookContainer->isRegistered( $key ) ) { + $this->hookContainer->clear( $key ); + } + } + + public function getOriginalArray(): array { + return $this->originalArray; + } +} diff --git a/includes/HookContainer/FauxHookHandlerArray.php b/includes/HookContainer/FauxHookHandlerArray.php new file mode 100644 index 000000000000..5b97b79ece9f --- /dev/null +++ b/includes/HookContainer/FauxHookHandlerArray.php @@ -0,0 +1,89 @@ +<?php + +namespace MediaWiki\HookContainer; + +use InvalidArgumentException; +use LogicException; +use OutOfBoundsException; + +/** + * @internal + */ +class FauxHookHandlerArray implements \ArrayAccess, \IteratorAggregate { + + private HookContainer $hookContainer; + + private string $name; + + private ?array $handlers = null; + + /** + * @param HookContainer $hookContainer + * @param string $name + */ + public function __construct( HookContainer $hookContainer, string $name ) { + $this->hookContainer = $hookContainer; + $this->name = $name; + } + + /** + * @inheritDoc + */ + #[\ReturnTypeWillChange] + public function offsetExists( $offset ) { + return $this->getHandler( $offset ) !== null; + } + + /** + * @inheritDoc + */ + #[\ReturnTypeWillChange] + public function offsetGet( $offset ) { + $handler = $this->getHandler( $offset ); + + if ( !$handler ) { + throw new OutOfBoundsException( "No such index in the handler list: $offset" ); + } + + return $handler; + } + + /** + * @inheritDoc + */ + #[\ReturnTypeWillChange] + public function offsetSet( $offset, $value ) { + if ( $offset !== null ) { + throw new InvalidArgumentException( '$offset must be null, this array is append only' ); + } + + $this->hookContainer->register( $this->name, $value ); + $this->handlers = null; + } + + /** + * @inheritDoc + * @return never + */ + #[\ReturnTypeWillChange] + public function offsetUnset( $offset ) { + throw new LogicException( 'unset is not supported for hook handler arrays' ); + } + + private function getHandler( $offset ) { + if ( $this->handlers === null ) { + $this->handlers = $this->hookContainer->getLegacyHandlers( $this->name ); + } + + return $this->handlers[$offset] ?? null; + } + + #[\ReturnTypeWillChange] + public function getIterator() { + if ( $this->handlers === null ) { + $this->handlers = $this->hookContainer->getLegacyHandlers( $this->name ); + } + + return new \ArrayIterator( $this->handlers ); + } +} diff --git a/includes/HookContainer/GlobalHookRegistry.php b/includes/HookContainer/GlobalHookRegistry.php deleted file mode 100644 index 961d7236ccf2..000000000000 --- a/includes/HookContainer/GlobalHookRegistry.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php - -namespace MediaWiki\HookContainer; - -use ExtensionRegistry; - -/** - * A HookRegistry which sources its data from dynamically changing sources: - * $wgHooks and an ExtensionRegistry. - */ -class GlobalHookRegistry implements HookRegistry { - /** @var ExtensionRegistry */ - private $extensionRegistry; - /** @var DeprecatedHooks */ - private $deprecatedHooks; - - public function __construct( - ExtensionRegistry $extensionRegistry, - DeprecatedHooks $deprecatedHooks - ) { - $this->extensionRegistry = $extensionRegistry; - $this->deprecatedHooks = $deprecatedHooks; - } - - public function getGlobalHooks() { - global $wgHooks; - return $wgHooks; - } - - public function getExtensionHooks() { - return $this->extensionRegistry->getAttribute( 'Hooks' ) ?? []; - } - - public function getDeprecatedHooks() { - return $this->deprecatedHooks; - } -} diff --git a/includes/HookContainer/HookContainer.php b/includes/HookContainer/HookContainer.php index 99b5a772d678..6d150a67097f 100644 --- a/includes/HookContainer/HookContainer.php +++ b/includes/HookContainer/HookContainer.php @@ -367,7 +367,7 @@ class HookContainer implements SalvageableService { * Attach an event handler to a given hook. * * @param string $hook Name of hook - * @param callable|string|array $callback handler object to attach + * @param mixed $callback handler object to attach */ public function register( string $hook, $callback ) { $deprecatedHooks = $this->registry->getDeprecatedHooks(); @@ -375,10 +375,11 @@ class HookContainer implements SalvageableService { if ( $deprecated ) { $info = $deprecatedHooks->getDeprecationInfo( $hook ); if ( empty( $info['silent'] ) ) { - $deprecatedVersion = $info['deprecatedVersion'] ?? false; - $component = $info['component'] ?? false; + $handler = $this->normalizeHandler( $callback, $hook ); wfDeprecated( - "$hook hook", $deprecatedVersion, $component + "$hook hook (used in " . $handler['functionName'] . ")", + $info['deprecatedVersion'] ?? false, + $info['component'] ?? false ); } } |