Completed
Pull Request — master (#326)
by Marco
07:03
created

LazyLoadingValueHolderPropertyAccessBench   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 199
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 4
dl 0
loc 199
rs 10
c 0
b 0
f 0

25 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 14 1
A benchEmptyClassInitialization() 0 4 1
A benchInitializedEmptyClassInitialization() 0 4 1
A benchObjectWithPublicPropertiesInitialization() 0 4 1
A benchInitializedObjectWithPublicPropertiesInitialization() 0 4 1
A benchObjectWithPublicPropertiesPropertyRead() 0 4 1
A benchInitializedObjectWithPublicPropertiesPropertyRead() 0 4 1
A benchObjectWithPublicPropertiesPropertyWrite() 0 4 1
A benchInitializedObjectWithPublicPropertiesPropertyWrite() 0 4 1
A benchObjectWithPublicPropertiesPropertyIsset() 0 6 1
A benchInitializedObjectWithPublicPropertiesPropertyIsset() 0 6 1
A benchObjectWithPublicPropertiesPropertyUnset() 0 4 1
A benchInitializedObjectWithPublicPropertiesPropertyUnset() 0 4 1
A benchObjectWithMixedPropertiesInitialization() 0 4 1
A benchInitializedObjectWithMixedPropertiesInitialization() 0 4 1
A benchObjectWithMixedPropertiesPropertyRead() 0 4 1
A benchInitializedObjectWithMixedPropertiesPropertyRead() 0 4 1
A benchObjectWithMixedPropertiesPropertyWrite() 0 4 1
A benchInitializedObjectWithMixedPropertiesPropertyWrite() 0 4 1
A benchObjectWithMixedPropertiesPropertyIsset() 0 6 1
A benchInitializedObjectWithMixedPropertiesPropertyIsset() 0 6 1
A benchObjectWithMixedPropertiesPropertyUnset() 0 4 1
A benchInitializedObjectWithMixedPropertiesPropertyUnset() 0 4 1
A buildProxy() 0 17 1
A generateProxyClass() 0 15 2
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license.
17
 */
18
19
declare(strict_types=1);
20
21
namespace ProxyManagerBench\Functional;
22
23
use PhpBench\Benchmark\Metadata\Annotations\BeforeMethods;
24
use ProxyManager\Generator\ClassGenerator;
25
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
26
use ProxyManager\Proxy\VirtualProxyInterface;
27
use ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator;
28
use ProxyManagerTestAsset\ClassWithMixedProperties;
29
use ProxyManagerTestAsset\ClassWithPublicProperties;
30
use ProxyManagerTestAsset\EmptyClass;
31
use ReflectionClass;
32
33
/**
34
 * Benchmark that provides results for state access/initialization time for lazy loading value holder proxies
35
 *
36
 * @author Marco Pivetta <[email protected]>
37
 * @license MIT
38
 *
39
 * @BeforeMethods({"setUp"})
40
 */
41
class LazyLoadingValueHolderPropertyAccessBench
42
{
43
    /**
44
     * @var EmptyClass|VirtualProxyInterface
45
     */
46
    private $emptyClassProxy;
47
48
    /**
49
     * @var EmptyClass|VirtualProxyInterface
50
     */
51
    private $initializedEmptyClassProxy;
52
53
    /**
54
     * @var ClassWithPublicProperties|VirtualProxyInterface
55
     */
56
    private $publicPropertiesProxy;
57
58
    /**
59
     * @var ClassWithPublicProperties|VirtualProxyInterface
60
     */
61
    private $initializedPublicPropertiesProxy;
62
63
    /**
64
     * @var ClassWithMixedProperties|VirtualProxyInterface
65
     */
66
    private $mixedPropertiesProxy;
67
68
    /**
69
     * @var ClassWithMixedProperties|VirtualProxyInterface
70
     */
71
    private $initializedMixedPropertiesProxy;
72
73
    public function setUp()
74
    {
75
        $this->emptyClassProxy          = $this->buildProxy(EmptyClass::class);
76
        $this->publicPropertiesProxy    = $this->buildProxy(ClassWithPublicProperties::class);
77
        $this->mixedPropertiesProxy     = $this->buildProxy(ClassWithMixedProperties::class);
78
79
        $this->initializedEmptyClassProxy          = $this->buildProxy(EmptyClass::class);
80
        $this->initializedPublicPropertiesProxy    = $this->buildProxy(ClassWithPublicProperties::class);
81
        $this->initializedMixedPropertiesProxy     = $this->buildProxy(ClassWithMixedProperties::class);
82
83
        $this->initializedEmptyClassProxy->initializeProxy();
84
        $this->initializedPublicPropertiesProxy->initializeProxy();
85
        $this->initializedMixedPropertiesProxy->initializeProxy();
86
    }
87
88
    public function benchEmptyClassInitialization()
89
    {
90
        $this->emptyClassProxy->initializeProxy();
1 ignored issue
show
Bug introduced by
The method initializeProxy does only exist in ProxyManager\Proxy\VirtualProxyInterface, but not in ProxyManagerTestAsset\EmptyClass.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
91
    }
92
93
    public function benchInitializedEmptyClassInitialization()
94
    {
95
        $this->initializedEmptyClassProxy->initializeProxy();
1 ignored issue
show
Bug introduced by
The method initializeProxy does only exist in ProxyManager\Proxy\VirtualProxyInterface, but not in ProxyManagerTestAsset\EmptyClass.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
96
    }
97
98
    public function benchObjectWithPublicPropertiesInitialization()
99
    {
100
        $this->publicPropertiesProxy->initializeProxy();
1 ignored issue
show
Bug introduced by
The method initializeProxy does only exist in ProxyManager\Proxy\VirtualProxyInterface, but not in ProxyManagerTestAsset\ClassWithPublicProperties.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
101
    }
102
103
    public function benchInitializedObjectWithPublicPropertiesInitialization()
104
    {
105
        $this->initializedPublicPropertiesProxy->initializeProxy();
1 ignored issue
show
Bug introduced by
The method initializeProxy does only exist in ProxyManager\Proxy\VirtualProxyInterface, but not in ProxyManagerTestAsset\ClassWithPublicProperties.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
106
    }
107
108
    public function benchObjectWithPublicPropertiesPropertyRead()
109
    {
110
        $this->publicPropertiesProxy->property0;
111
    }
112
113
    public function benchInitializedObjectWithPublicPropertiesPropertyRead()
114
    {
115
        $this->initializedPublicPropertiesProxy->property0;
116
    }
117
118
    public function benchObjectWithPublicPropertiesPropertyWrite()
119
    {
120
        $this->publicPropertiesProxy->property0 = 'foo';
121
    }
122
123
    public function benchInitializedObjectWithPublicPropertiesPropertyWrite()
124
    {
125
        $this->initializedPublicPropertiesProxy->property0 = 'foo';
126
    }
127
128
    public function benchObjectWithPublicPropertiesPropertyIsset()
129
    {
130
        /** @noinspection PhpExpressionResultUnusedInspection */
131
        /** @noinspection UnSafeIsSetOverArrayInspection */
132
        isset($this->publicPropertiesProxy->property0);
133
    }
134
135
    public function benchInitializedObjectWithPublicPropertiesPropertyIsset()
136
    {
137
        /** @noinspection PhpExpressionResultUnusedInspection */
138
        /** @noinspection UnSafeIsSetOverArrayInspection */
139
        isset($this->initializedPublicPropertiesProxy->property0);
140
    }
141
142
    public function benchObjectWithPublicPropertiesPropertyUnset()
143
    {
144
        unset($this->publicPropertiesProxy->property0);
145
    }
146
147
    public function benchInitializedObjectWithPublicPropertiesPropertyUnset()
148
    {
149
        unset($this->initializedPublicPropertiesProxy->property0);
150
    }
151
152
    public function benchObjectWithMixedPropertiesInitialization()
153
    {
154
        $this->mixedPropertiesProxy->initializeProxy();
1 ignored issue
show
Bug introduced by
The method initializeProxy does only exist in ProxyManager\Proxy\VirtualProxyInterface, but not in ProxyManagerTestAsset\ClassWithMixedProperties.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
155
    }
156
157
    public function benchInitializedObjectWithMixedPropertiesInitialization()
158
    {
159
        $this->initializedMixedPropertiesProxy->initializeProxy();
1 ignored issue
show
Bug introduced by
The method initializeProxy does only exist in ProxyManager\Proxy\VirtualProxyInterface, but not in ProxyManagerTestAsset\ClassWithMixedProperties.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
160
    }
161
162
    public function benchObjectWithMixedPropertiesPropertyRead()
163
    {
164
        $this->mixedPropertiesProxy->publicProperty0;
165
    }
166
167
    public function benchInitializedObjectWithMixedPropertiesPropertyRead()
168
    {
169
        $this->initializedMixedPropertiesProxy->publicProperty0;
170
    }
171
172
    public function benchObjectWithMixedPropertiesPropertyWrite()
173
    {
174
        $this->mixedPropertiesProxy->publicProperty0 = 'foo';
175
    }
176
177
    public function benchInitializedObjectWithMixedPropertiesPropertyWrite()
178
    {
179
        $this->initializedMixedPropertiesProxy->publicProperty0 = 'foo';
180
    }
181
182
    public function benchObjectWithMixedPropertiesPropertyIsset()
183
    {
184
        /** @noinspection PhpExpressionResultUnusedInspection */
185
        /** @noinspection UnSafeIsSetOverArrayInspection */
186
        isset($this->mixedPropertiesProxy->publicProperty0);
187
    }
188
189
    public function benchInitializedObjectWithMixedPropertiesPropertyIsset()
190
    {
191
        /** @noinspection PhpExpressionResultUnusedInspection */
192
        /** @noinspection UnSafeIsSetOverArrayInspection */
193
        isset($this->initializedMixedPropertiesProxy->publicProperty0);
194
    }
195
196
    public function benchObjectWithMixedPropertiesPropertyUnset()
197
    {
198
        unset($this->mixedPropertiesProxy->publicProperty0);
199
    }
200
201
    public function benchInitializedObjectWithMixedPropertiesPropertyUnset()
202
    {
203
        unset($this->initializedMixedPropertiesProxy->publicProperty0);
204
    }
205
206
    private function buildProxy(string $originalClass) : VirtualProxyInterface
207
    {
208
        return ($this->generateProxyClass($originalClass))::staticProxyConstructor(
1 ignored issue
show
Bug introduced by
The method staticProxyConstructor cannot be called on $this->generateProxyClass($originalClass) (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
209
            function (
210
                & $valueHolder,
211
                VirtualProxyInterface $proxy,
212
                string $method,
213
                $params,
214
                & $initializer
215
            ) use ($originalClass) : bool {
216
                $initializer = null;
217
                $valueHolder = new $originalClass();
218
219
                return true;
220
            }
221
        );
222
    }
223
224
    private function generateProxyClass(string $originalClassName) : string
225
    {
226
        $generatedClassName = __CLASS__ . '\\' . $originalClassName;
227
228
        if (class_exists($generatedClassName)) {
229
            return $generatedClassName;
230
        }
231
232
        $generatedClass     = new ClassGenerator($generatedClassName);
233
234
        (new LazyLoadingValueHolderGenerator())->generate(new ReflectionClass($originalClassName), $generatedClass);
235
        (new EvaluatingGeneratorStrategy())->generate($generatedClass);
236
237
        return $generatedClassName;
238
    }
239
}
240