PluginProbe
Metricool – Social media and site statistics / trunk
Metricool – Social media and site statistics vtrunk
2.1.0 2.0.2 2.0.1 2.0.0 1.27 trunk
metricool / app / Support / Helpers / DeferredObject.php

DeferredObject.php in Metricool – Social media and site statistics trunk, at app/Support/Helpers/DeferredObject.php

89 lines 2.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Metricool\Support\Helpers;
6
7 /**
8 * Deferred object helper class to delay the instantiation of a class until
9 * one of its methods is called. See for example {@see GeneralConfig}.
10 */
11 abstract class DeferredObject
12 {
13 /**
14 * Return the class-string of the class you want to instantiate on the first
15 * method call.
16 * @return class-string
17 */
18 abstract protected function deferredClassString(): string;
19
20 /**
21 * The key should reflect the constructor argument for the deferred class.
22 * @return array
23 */
24 abstract protected function deferredConstructArguments(): array;
25
26 /**
27 * Cache a single deferred instance. This class intentionally only stores
28 * one instance. Call {@see clearDeferredInstance} when you need to force a
29 * re-instantiation (for example, when the constructor inputs have changed).
30 * @var object|null
31 */
32 private ?object $deferredInstance = null;
33
34 /**
35 * Clear the cached deferred instance. Useful when the construction inputs
36 * change during runtime, and you want to force a re-instantiation.
37 */
38 protected function clearDeferredInstance(): void
39 {
40 $this->deferredInstance = null;
41 }
42
43 /**
44 * Retrieve the cached instance or create a new one and cache it.
45 *
46 * Note: this method only caches a single instance. If you need to change
47 * the underlying construction inputs, call {@see clearDeferredInstance}
48 * to force recreation.
49 *
50 * @throws \ReflectionException
51 */
52 private function getDeferredInstance(): object
53 {
54 if ($this->deferredInstance !== null) {
55 return $this->deferredInstance;
56 }
57
58 $classString = $this->deferredClassString();
59 $constructArgs = $this->deferredConstructArguments();
60
61 $reflectionClass = new \ReflectionClass($classString);
62 $instance = $reflectionClass->newInstanceArgs($constructArgs);
63
64 $this->deferredInstance = $instance;
65
66 return $instance;
67 }
68
69 /**
70 * Magic method to forward method calls to the deferred instance.
71 * @return mixed
72 * @throws \ReflectionException
73 */
74 public function __call(string $name, array $arguments)
75 {
76 $instance = $this->getDeferredInstance();
77
78 // If the method is public and callable, call it directly for speed.
79 if (is_callable([$instance, $name])) {
80 return $instance->$name(...$arguments);
81 }
82
83 $reflectionClass = new \ReflectionClass($instance);
84
85 $method = $reflectionClass->getMethod($name);
86 return $method->invokeArgs($instance, $arguments);
87 }
88 }
89