PhpDecoratedObject   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 73
Duplicated Lines 0 %

Test Coverage

Coverage 91.67%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 13
eloc 24
c 1
b 1
f 0
dl 0
loc 73
ccs 22
cts 24
cp 0.9167
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A newInstanceOf() 0 16 4
A __construct() 0 6 1
A getBody() 0 3 1
A newInstance() 0 3 1
A cloneProperties() 0 17 6
1
<?php
2
3
namespace Exsio\PhpObjectDecorator;
4
5
class PhpDecoratedObject
6
{
7
8 4
    public function __construct(
9
        private readonly string $body,
10
        private readonly object $obj,
11
        private readonly string $className,
12
13
    ) {
14
    }
15
16
    /**
17
     * @return string
18
     */
19 2
    public function getBody(): string
20
    {
21 2
        return $this->body;
22
    }
23
24
    /**
25
     * @return object
26
     */
27 1
    public function newInstance(): object
28
    {
29
        return self::newInstanceOf($this->className, $this->body, $this->obj);
30 1
    }
31 1
32
    /**
33 1
     * @return object
34 1
     */
35 1
    public static function newInstanceOf(string $className, string $body, object $obj): object
36
    {
37 1
        try {
38
            if (!class_exists($className)) {
39 1
                eval($body);
40
            }
41
            $reflector = new \ReflectionClass($className);
42
            $instance  = $reflector->newInstanceWithoutConstructor();
43
            self::cloneProperties($instance, get_class($obj), $obj);
44
45
            return $instance;
46
        } catch (\Throwable $error) {
47
            if ($error instanceof PhpObjectDecoratorException) {
48
                throw $error;
49
            }
50
            throw new PhpObjectDecoratorException("Unable to Instantiate Decorated Class: ", $error);
51
        }
52 1
    }
53
54 1
    /**
55 1
     * @param mixed  $instance
56 1
     * @param string $class
57 1
     *
58 1
     * @return void
59 1
     * @throws \ReflectionException
60
     */
61
    private static function cloneProperties(mixed $instance, string $class, object $obj): void
62 1
    {
63 1
        $reflector  = new \ReflectionClass($class);
64
        $properties = $reflector->getProperties();
65 1
        foreach ($properties as $property) {
66 1
            //sometimes \ReflectionClass returns properties from the subclasses, and that can cause
67
            //an error, when trying to set a readonly property value from invalid scope
68
            if ($property->isInitialized($obj) && $property->getDeclaringClass()->getName() === $class) {
69
                $originalValue = $property->getValue($obj);
70
                $property->setValue($instance, $originalValue);
71
            }
72
        }
73
        foreach ($reflector->getTraits() as $traitClass) {
74
            self::cloneProperties($instance, $traitClass->getName(), $obj);
75
        }
76
        if ($reflector->getParentClass()) {
77
            self::cloneProperties($instance, $reflector->getParentClass()->getName(), $obj);
78
        }
79
    }
80
81
82
}