ObjectEncoder   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 47
c 1
b 0
f 0
dl 0
loc 124
rs 10
wmc 21

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getObjectArray() 0 15 4
A encodeObjectArray() 0 13 4
A getDefaultOptions() 0 3 1
A getObjectState() 0 20 3
A supports() 0 3 1
A encodeObject() 0 11 4
A encode() 0 11 4
1
<?php
2
3
namespace Riimu\Kit\PHPEncoder\Encoder;
4
5
/**
6
 * Encoder for generic objects.
7
 * @author Riikka Kalliomäki <[email protected]>
8
 * @copyright Copyright (c) 2014-2020 Riikka Kalliomäki
9
 * @license http://opensource.org/licenses/mit-license.php MIT License
10
 */
11
class ObjectEncoder implements Encoder
12
{
13
    /** @var array Default values for options in the encoder */
14
    private static $defaultOptions = [
15
        'object.method' => true,
16
        'object.format' => 'vars',
17
        'object.cast' => true,
18
    ];
19
20
    public function getDefaultOptions()
21
    {
22
        return self::$defaultOptions;
23
    }
24
25
    public function supports($value)
26
    {
27
        return \is_object($value);
28
    }
29
30
    public function encode($value, $depth, array $options, callable $encode)
31
    {
32
        if ($options['object.method']) {
33
            if (method_exists($value, 'toPHP')) {
34
                return (string) $value->toPHP();
35
            } elseif (method_exists($value, 'toPHPValue')) {
36
                return $encode($value->toPHPValue());
37
            }
38
        }
39
40
        return $this->encodeObject($value, $options, $encode);
41
    }
42
43
    /**
44
     * Encodes the object as string according to encoding options.
45
     * @param object $object Object to encode as PHP
46
     * @param array $options List of encoder options
47
     * @param callable $encode Callback used to encode values
48
     * @return string The object encoded as string
49
     */
50
    private function encodeObject($object, array $options, callable $encode)
51
    {
52
        if ($options['object.format'] === 'string') {
53
            return $encode((string) $object);
54
        } elseif ($options['object.format'] === 'serialize') {
55
            return sprintf('unserialize(%s)', $encode(serialize($object)));
56
        } elseif ($options['object.format'] === 'export') {
57
            return sprintf('\\%s::__set_state(%s)', \get_class($object), $encode($this->getObjectState($object)));
58
        }
59
60
        return $this->encodeObjectArray($object, $options, $encode);
61
    }
62
63
    /**
64
     * Encodes the object into one of the array formats.
65
     * @param object $object Object to encode as PHP
66
     * @param array $options List of encoder options
67
     * @param callable $encode Callback used to encode values
68
     * @return string The object encoded as string
69
     * @throws \RuntimeException If the object format is invalid
70
     */
71
    private function encodeObjectArray($object, array $options, callable $encode)
72
    {
73
        if (!\in_array((string) $options['object.format'], ['array', 'vars', 'iterate'], true)) {
74
            throw new \RuntimeException('Invalid object encoding format: ' . $options['object.format']);
75
        }
76
77
        $output = $encode($this->getObjectArray($object, $options['object.format']));
78
79
        if ($options['object.cast']) {
80
            $output = '(object)' . ($options['whitespace'] ? ' ' : '') . $output;
81
        }
82
83
        return $output;
84
    }
85
86
    /**
87
     * Converts the object into array that can be encoded.
88
     * @param object $object Object to convert to an array
89
     * @param string $format Object conversion format
90
     * @return array The object converted into an array
91
     * @throws \RuntimeException If object conversion format is invalid
92
     */
93
    private function getObjectArray($object, $format)
94
    {
95
        if ($format === 'array') {
96
            return (array) $object;
97
        } elseif ($format === 'vars') {
98
            return get_object_vars($object);
99
        }
100
101
        $array = [];
102
103
        foreach ($object as $key => $value) {
104
            $array[$key] = $value;
105
        }
106
107
        return $array;
108
    }
109
110
    /**
111
     * Returns an array of object properties as would be generated by var_export.
112
     * @param object $object Object to turn into array
113
     * @return array Properties of the object as passed to var_export
114
     */
115
    private function getObjectState($object)
116
    {
117
        $class = new \ReflectionClass($object);
118
        $visibility = \ReflectionProperty::IS_PRIVATE
119
            | \ReflectionProperty::IS_PROTECTED
120
            | \ReflectionProperty::IS_PUBLIC;
121
        $values = [];
122
123
        do {
124
            foreach ($class->getProperties($visibility) as $property) {
125
                $property->setAccessible(true);
126
                $values[$property->getName()] = $property->getValue($object);
127
            }
128
129
            $class = $class->getParentClass();
130
            $visibility = \ReflectionProperty::IS_PRIVATE;
131
        } while ($class !== false);
132
133
        // Use get_object_vars to include dynamic properties
134
        return $values + get_object_vars($object);
135
    }
136
}
137