Completed
Push — master ( ea2531...f7d4c1 )
by Tobias
03:55
created

Reflection::invokeMethod()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 5

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 29
ccs 17
cts 17
cp 1
rs 8.439
cc 5
eloc 18
nc 5
nop 0
crap 5
1
<?php
2
3
namespace Nyholm\Reflection;
4
5
use Webmozart\Assert\Assert;
6
7
/**
8
 * Warning: This class should only be used with tests, fixtures or debug.
9
 *
10
 * @author Tobias Nyholm <[email protected]>
11
 */
12
class Reflection
13
{
14
    /**
15
     * Get a property of an object.
16
     *
17
     * @param object|string $objectOrClass
18
     * @param string        $propertyName
19
     *
20
     * @return mixed
21
     *
22
     * @throws \InvalidArgumentException
23
     */
24 24
    public static function getProperty($objectOrClass, $propertyName)
25
    {
26 24
        return static::getAccessibleReflectionProperty($objectOrClass, $propertyName)->getValue($objectOrClass);
27
    }
28
29
    /**
30
     * Set a property to an object.
31
     *
32
     * @param object|string $objectOrClass
33
     * @param string        $propertyName
34
     * @param mixed         $value
35
     *
36
     * @throws \InvalidArgumentException
37
     */
38 9
    public static function setProperty($objectOrClass, $propertyName, $value)
39
    {
40 9
        static::getAccessibleReflectionProperty($objectOrClass, $propertyName)->setValue($objectOrClass, $value);
41 9
    }
42
43
    /**
44
     * Invoke a method on a object and get the return values.
45
     *
46
     * @param object|string $objectOrClass
1 ignored issue
show
Bug introduced by
There is no parameter named $objectOrClass. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
47
     * @param string        $methodName
48
     * @param mixed ...$params
49
     *
50
     * @return mixed
51
     *
52
     * @throws \InvalidArgumentException
53
     */
54 15
    public static function invokeMethod()
55
    {
56 15
        if (func_num_args() < 2) {
57 2
            throw new \LogicException('The method Reflection::invokeMethod need at least two arguments.');
58
        }
59
60 13
        $arguments = func_get_args();
61 13
        $objectOrClass = array_shift($arguments);
62 13
        $methodName = array_shift($arguments);
63
64 13
        Assert::string($methodName, 'Method name has to be a string. Variable of type "%s" was given.');
65 10
        if (is_string($objectOrClass)) {
66 3
            Assert::classExists($objectOrClass, 'Could not find class "%s"');
67
        } else {
68 7
            Assert::notInstanceOf($objectOrClass, '\stdClass', 'Can not get a method of \stdClass.');
69 6
            Assert::object($objectOrClass, 'Can not get a property of a non object. Variable of type "%s" was given.');
70
        }
71
72 7
        $refl = new \ReflectionClass($objectOrClass);
73 7
        if (!$refl->hasMethod($methodName)) {
74 1
            throw new \LogicException(sprintf('The method %s::%s does not exist.', get_class($objectOrClass), $methodName));
75
        }
76
77 6
        $method = $refl->getMethod($methodName);
78 6
        $method->setAccessible(true);
79
80
        // If it is a static call we should pass null as first parameter.
81 6
        return $method->invokeArgs(is_string($objectOrClass) ? null : $objectOrClass, $arguments);
82
    }
83
84
    /**
85
     * Get a reflection class that has this property.
86
     *
87
     * @param string $class
88
     * @param string $propertyName
89
     *
90
     * @return \ReflectionClass|null
91
     */
92 20
    protected static function getReflectionClassWithProperty($class, $propertyName)
93
    {
94 20
        Assert::string($class, 'First argument to Reflection::getReflectionClassWithProperty must be string. Variable of type "%s" was given.');
95 20
        Assert::classExists($class, 'Could not find class "%s"');
96
97 19
        $refl = new \ReflectionClass($class);
98 19
        if ($refl->hasProperty($propertyName)) {
99 18
            return $refl;
100
        }
101
102 9
        if (false === $parent = get_parent_class($class)) {
103
            // No more parents
104 1
            return;
105
        }
106
107 9
        return self::getReflectionClassWithProperty($parent, $propertyName);
108
    }
109
110
    /**
111
     * Get an reflection property that you can access directly.
112
     *
113
     * @param object|string $objectOrClass
114
     * @param string        $propertyName
115
     *
116
     * @return \ReflectionProperty
117
     *
118
     * @throws \InvalidArgumentException
119
     * @throws \LogicException           if the property is not found on the object
120
     */
121 24
    protected static function getAccessibleReflectionProperty($objectOrClass, $propertyName)
122
    {
123 24
        Assert::string($propertyName, 'Property name must be a string. Variable of type "%s" was given.');
124
125 22
        if (is_string($objectOrClass)) {
126 4
            $class = $objectOrClass;
127
        } else {
128 18
            Assert::object($objectOrClass, 'Can not get a property of a non object. Variable of type "%s" was given.');
129 16
            Assert::notInstanceOf($objectOrClass, '\stdClass', 'Can not get a property of \stdClass.');
130 15
            $class = get_class($objectOrClass);
131
        }
132
133 19
        if (null === $refl = static::getReflectionClassWithProperty($class, $propertyName)) {
134 1
            throw new \LogicException(sprintf('The property %s does not exist on %s or any of its parents.', $propertyName, $class));
135
        }
136
137 18
        $property = $refl->getProperty($propertyName);
138 18
        $property->setAccessible(true);
139
140 18
        return $property;
141
    }
142
}
143