1<?php
2
3namespace DeepCopy\Reflection;
4
5use DeepCopy\Exception\PropertyException;
6use ReflectionClass;
7use ReflectionException;
8use ReflectionObject;
9use ReflectionProperty;
10
11class ReflectionHelper
12{
13    /**
14     * Retrieves all properties (including private ones), from object and all its ancestors.
15     *
16     * Standard \ReflectionClass->getProperties() does not return private properties from ancestor classes.
17     *
18     * @author muratyaman@gmail.com
19     * @see http://php.net/manual/en/reflectionclass.getproperties.php
20     *
21     * @param ReflectionClass $ref
22     *
23     * @return ReflectionProperty[]
24     */
25    public static function getProperties(ReflectionClass $ref)
26    {
27        $props = $ref->getProperties();
28        $propsArr = array();
29
30        foreach ($props as $prop) {
31            $propertyName = $prop->getName();
32            $propsArr[$propertyName] = $prop;
33        }
34
35        if ($parentClass = $ref->getParentClass()) {
36            $parentPropsArr = self::getProperties($parentClass);
37            foreach ($propsArr as $key => $property) {
38                $parentPropsArr[$key] = $property;
39            }
40
41            return $parentPropsArr;
42        }
43
44        return $propsArr;
45    }
46
47    /**
48     * Retrieves property by name from object and all its ancestors.
49     *
50     * @param object|string $object
51     * @param string $name
52     *
53     * @throws PropertyException
54     * @throws ReflectionException
55     *
56     * @return ReflectionProperty
57     */
58    public static function getProperty($object, $name)
59    {
60        $reflection = is_object($object) ? new ReflectionObject($object) : new ReflectionClass($object);
61
62        if ($reflection->hasProperty($name)) {
63            return $reflection->getProperty($name);
64        }
65
66        if ($parentClass = $reflection->getParentClass()) {
67            return self::getProperty($parentClass->getName(), $name);
68        }
69
70        throw new PropertyException(
71            sprintf(
72                'The class "%s" doesn\'t have a property with the given name: "%s".',
73                is_object($object) ? get_class($object) : $object,
74                $name
75            )
76        );
77    }
78}
79