aboutsummaryrefslogtreecommitdiffstats
path: root/includes/HookContainer
diff options
context:
space:
mode:
authordaniel <dkinzler@wikimedia.org>2022-10-25 16:03:05 +0200
committerdaniel <dkinzler@wikimedia.org>2023-03-09 10:20:44 +0100
commitdb729e46f6da1381ed36aa965fd768ed22809cba (patch)
tree745270ec6df1399413d6c49ac5d5eda2032d3a25 /includes/HookContainer
parentd19f30cedeb94a0a711f8e440df3c21992b8217d (diff)
downloadmediawikicore-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.php77
-rw-r--r--includes/HookContainer/FauxHookHandlerArray.php89
-rw-r--r--includes/HookContainer/GlobalHookRegistry.php37
-rw-r--r--includes/HookContainer/HookContainer.php9
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
);
}
}