ObjectProxy   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 115
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 19
c 3
b 1
f 0
dl 0
loc 115
ccs 23
cts 23
cp 1
rs 10
wmc 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getInstance() 0 3 1
A __construct() 0 6 1
A afterCall() 0 7 1
A processResult() 0 7 3
A callInternal() 0 4 1
A getNewStaticInstance() 0 6 1
A call() 0 16 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Proxy;
6
7
use Throwable;
8
9
/**
10
 * Base proxy class for objects to use in {@see ProxyManager}. A concrete implementation can be provided too.
11
 */
12
class ObjectProxy
13
{
14
    use ProxyTrait;
15
16 10
    public function __construct(
17
        /**
18
         * @var object An instance of the class for proxying method calls.
19
         */
20
        private object $instance
21
    ) {
22 10
    }
23
24
    /**
25
     * Gets instance.
26
     *
27
     * @return object {@see $instance}.
28
     */
29 1
    public function getInstance(): object
30
    {
31 1
        return $this->instance;
32
    }
33
34
    /**
35
     * Calls a method in the {@see $instance} additionally allowing to process result afterwards (even in case of
36
     * error).
37
     *
38
     * @param string $methodName A called method in the {@see $instance}.
39
     * @param array $arguments A list of arguments passed to a called method. The order must be maintained.
40
     *
41
     * @throws Throwable In case of error happen during the method call.
42
     *
43
     * @return $this|mixed Either a new instance of {@see $instance} class or return value of a called method.
44
     */
45 9
    protected function call(string $methodName, array $arguments): mixed
46
    {
47 9
        $this->resetCurrentError();
48 9
        $result = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
49 9
        $timeStart = microtime(true);
50
        try {
51
            /** @var mixed $result */
52 9
            $result = $this->callInternal($methodName, $arguments);
53 3
        } catch (Throwable $e) {
54 3
            $this->repeatError($e);
55
        } finally {
56
            /** @var mixed $result */
57 9
            $result = $this->afterCall($methodName, $arguments, $result, $timeStart);
0 ignored issues
show
Bug introduced by
It seems like $timeStart can also be of type string; however, parameter $timeStart of Yiisoft\Proxy\ObjectProxy::afterCall() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

57
            $result = $this->afterCall($methodName, $arguments, $result, /** @scrutinizer ignore-type */ $timeStart);
Loading history...
58
        }
59
60 6
        return $this->processResult($result);
61
    }
62
63
    /**
64
     * An event executed after each call of a method. Can be used for handling errors, logging, etc. `$result` must be
65
     * always returned.
66
     *
67
     * @param string $methodName A called method in the {@see $instance}.
68
     * @param array $arguments A list of arguments passed to a called method. The order must be maintained.
69
     * @param mixed $result Return value of a called method.
70
     * @param float $timeStart UNIX timestamp right before proxy method call. For example: `1656657586.4849`.
71
     *
72
     * @return mixed Return value of a called method.
73
     */
74 9
    protected function afterCall(
75
        string $methodName,
76
        array $arguments,
77
        mixed $result,
78
        float $timeStart
79
    ): mixed {
80 9
        return $result;
81
    }
82
83
    /**
84
     * Gets new instance of {@see $instance} class.
85
     *
86
     * @param object $instance {@see $instance}.
87
     *
88
     * @return $this A new instance of the same class
89
     */
90 1
    protected function getNewStaticInstance(object $instance): self
91
    {
92
        /**
93
         * @psalm-suppress UnsafeInstantiation Constructor should be consistent to `getNewStaticInstance()`.
94
         */
95 1
        return new static($instance);
96
    }
97
98
    /**
99
     * Just calls a method in the {@see $instance}.
100
     *
101
     * @param string $methodName A called method in the {@see $instance}.
102
     * @param array $arguments A list of arguments passed to a called method. The order must be maintained.
103
     *
104
     * @return mixed Return value of a called method.
105
     */
106 9
    private function callInternal(string $methodName, array $arguments): mixed
107
    {
108
        /** @psalm-suppress MixedMethodCall */
109 9
        return $this->instance->$methodName(...$arguments);
110
    }
111
112
    /**
113
     * Processes return value of a called method - if it's an instance of the same class in {@see $instance} - a new
114
     * instance is created, otherwise it's returned as is.
115
     *
116
     * @param mixed $result Return value of a called method.
117
     *
118
     * @return $this|mixed Either a new instance of {@see $instance} class or return value of a called method.
119
     */
120 6
    private function processResult(mixed $result): mixed
121
    {
122 6
        if (is_object($result) && get_class($result) === get_class($this->instance)) {
123 1
            $result = $this->getNewStaticInstance($result);
124
        }
125
126 6
        return $result;
127
    }
128
}
129