Merge pull request #22840 from braders/prefered-language-undefined-variable
[civicrm-core.git] / Civi / Core / Event / ServiceListener.php
1 <?php
2
3 namespace Civi\Core\Event;
4
5 /**
6 * A ServiceListener is a `callable` (supporting "__invoke()") which references
7 * a method of a service-object.
8 *
9 * The following two callables are conceptually similar:
10 *
11 * (A) addListener('some.event', [Civi::service('foo'), 'doBar']);
12 * (B) addListener('some.event', new ServiceListener(['foo', 'doBar']));
13 *
14 * The difference is that (A) immediately instantiates the 'foo' service,
15 * whereas (B) instantiates `foo` lazily. (B) is more amenable to serialization,
16 * caching, etc. If you have a long-tail of many services/listeners/etc that
17 * are not required for every page-load, then (B) should perform better.
18 *
19 * @package Civi\Core\Event
20 */
21 class ServiceListener {
22
23 /**
24 * @var array
25 * Ex: ['service_name', 'someMethod']
26 */
27 private $inertCb = NULL;
28
29 /**
30 * @var array|null
31 * Ex: [$svcObj, 'someMethod']
32 */
33 private $liveCb = NULL;
34
35 /**
36 * @var \Symfony\Component\DependencyInjection\ContainerInterface
37 */
38 private $container = NULL;
39
40 /**
41 * @param array $callback
42 * Ex: ['service_name', 'someMethod']
43 */
44 public function __construct($callback) {
45 $this->inertCb = $callback;
46 }
47
48 public function __invoke(...$args) {
49 if ($this->liveCb === NULL) {
50 $c = $this->container ?: \Civi::container();
51 $this->liveCb = [$c->get($this->inertCb[0]), $this->inertCb[1]];
52 }
53 return call_user_func_array($this->liveCb, $args);
54 }
55
56 public function __toString() {
57 $class = NULL;
58 if (\Civi\Core\Container::isContainerBooted()) {
59 try {
60 $c = $this->container ?: \Civi::container();
61 $class = $c->findDefinition($this->inertCb[0])->getClass();
62 }
63 catch (Throwable $t) {
64 }
65 }
66 if ($class) {
67 return sprintf('$(%s)->%s($e) [%s]', $this->inertCb[0], $this->inertCb[1], $class);
68 }
69 else {
70 return sprintf('\$(%s)->%s($e)', $this->inertCb[0], $this->inertCb[1]);
71 }
72 }
73
74 public function __sleep() {
75 return ['inertCb'];
76 }
77
78 /**
79 * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
80 * @return static
81 */
82 public function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container) {
83 $this->container = $container;
84 return $this;
85 }
86
87 }