Completed
Push — master ( 3be072...ba2d3a )
by Marco
231:32 queued 209:55
created

MagicGet   A

Complexity

Total Complexity 2

Size/Duplication

Total Lines 107
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 0
loc 107
c 0
b 0
f 0
wmc 2
lcom 0
cbo 2
ccs 22
cts 22
cp 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ProxyManager\ProxyGenerator\LazyLoadingGhost\MethodGenerator;
6
7
use InvalidArgumentException;
8
use ProxyManager\Generator\MagicMethodGenerator;
9
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\InitializationTracker;
10
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\PrivatePropertiesMap;
11
use ProxyManager\ProxyGenerator\LazyLoadingGhost\PropertyGenerator\ProtectedPropertiesMap;
12
use ProxyManager\ProxyGenerator\PropertyGenerator\PublicPropertiesMap;
13
use ProxyManager\ProxyGenerator\Util\PublicScopeSimulator;
14
use ReflectionClass;
15
use Zend\Code\Generator\MethodGenerator;
16
use Zend\Code\Generator\ParameterGenerator;
17
use Zend\Code\Generator\PropertyGenerator;
18
use function sprintf;
19
20
/**
21
 * Magic `__get` for lazy loading ghost objects
22
 */
23
class MagicGet extends MagicMethodGenerator
24
{
25
    private string $callParentTemplate =  <<<'PHP'
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_STRING, expecting T_FUNCTION or T_CONST
Loading history...
26
$this->%s && ! $this->%s && $this->%s('__get', array('name' => $name));
27
28
if (isset(self::$%s[$name])) {
29
    return $this->$name;
30
}
31
32
if (isset(self::$%s[$name])) {
33
    if ($this->%s) {
34
        return $this->$name;
35
    }
36
37
    // check protected property access via compatible class
38
    $callers      = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
39
    $caller       = isset($callers[1]) ? $callers[1] : [];
40
    $object       = isset($caller['object']) ? $caller['object'] : '';
41
    $expectedType = self::$%s[$name];
42
43
    if ($object instanceof $expectedType) {
44
        return $this->$name;
45
    }
46
47
    $class = isset($caller['class']) ? $caller['class'] : '';
48
49
    if ($class === $expectedType || is_subclass_of($class, $expectedType) || $class === 'ReflectionProperty') {
50
        return $this->$name;
51
    }
52
} elseif (isset(self::$%s[$name])) {
53
    // check private property access via same class
54
    $callers = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
55
    $caller  = isset($callers[1]) ? $callers[1] : [];
56
    $class   = isset($caller['class']) ? $caller['class'] : '';
57
58
    static $accessorCache = [];
59
60
    if (isset(self::$%s[$name][$class])) {
61
        $cacheKey = $class . '#' . $name;
62
        $accessor = isset($accessorCache[$cacheKey])
63
            ? $accessorCache[$cacheKey]
64
            : $accessorCache[$cacheKey] = \Closure::bind(function & ($instance) use ($name) {
65
                return $instance->$name;
66
            }, null, $class);
67
68
        return $accessor($this);
69
    }
70
71
    if ($this->%s || 'ReflectionProperty' === $class) {
72
        $tmpClass = key(self::$%s[$name]);
73
        $cacheKey = $tmpClass . '#' . $name;
74
        $accessor = isset($accessorCache[$cacheKey])
75
            ? $accessorCache[$cacheKey]
76
            : $accessorCache[$cacheKey] = \Closure::bind(function & ($instance) use ($name) {
77
                return $instance->$name;
78
            }, null, $tmpClass);
79
80
        return $accessor($this);
81
    }
82
}
83
84
%s
85
PHP;
86
87
    /**
88
     * @throws InvalidArgumentException
89
     */
90
    public function __construct(
91
        ReflectionClass $originalClass,
92
        PropertyGenerator $initializerProperty,
93
        MethodGenerator $callInitializer,
94 2
        PublicPropertiesMap $publicProperties,
95
        ProtectedPropertiesMap $protectedProperties,
96
        PrivatePropertiesMap $privateProperties,
97
        InitializationTracker $initializationTracker
98
    ) {
99
        parent::__construct($originalClass, '__get', [new ParameterGenerator('name')]);
100
101
        $override = $originalClass->hasMethod('__get');
102
103 2
        $parentAccess = 'return parent::__get($name);';
104
105 2
        if (! $override) {
106
            $parentAccess = PublicScopeSimulator::getPublicAccessSimulationCode(
107 2
                PublicScopeSimulator::OPERATION_GET,
108
                'name'
109 2
            );
110 1
        }
111 1
112 1
        $this->setBody(sprintf(
113
            $this->callParentTemplate,
114
            $initializerProperty->getName(),
115
            $initializationTracker->getName(),
116 2
            $callInitializer->getName(),
117 2
            $publicProperties->getName(),
118 2
            $protectedProperties->getName(),
119 2
            $initializationTracker->getName(),
120 2
            $protectedProperties->getName(),
121 2
            $privateProperties->getName(),
122 2
            $privateProperties->getName(),
123 2
            $initializationTracker->getName(),
124 2
            $privateProperties->getName(),
125 2
            $parentAccess
126 2
        ));
127 2
    }
128
}
129