12
12
namespace Symfony \Component \Cache \Marshaller ;
13
13
14
14
use Symfony \Component \Cache \Marshaller \PhpMarshaller \Configurator ;
15
+ use Symfony \Component \Cache \Marshaller \PhpMarshaller \Marshaller ;
15
16
use Symfony \Component \Cache \Marshaller \PhpMarshaller \Reference ;
16
17
use Symfony \Component \Cache \Marshaller \PhpMarshaller \Registry ;
18
+ use Symfony \Component \Cache \Marshaller \PhpMarshaller \Values ;
17
19
18
20
/**
19
21
* @author Nicolas Grekas <[email protected] >
27
29
*/
28
30
class PhpMarshaller
29
31
{
30
- public static function marshall ($ value , int &$ objectsCount )
32
+ public static function marshall ($ value , bool &$ isStaticValue = null ): string
31
33
{
32
- if (!\is_object ($ value ) && !\is_array ($ value )) {
33
- return $ value ;
34
+ $ isStaticValue = true ;
35
+
36
+ if (!\is_object ($ value ) && !(\is_array ($ value ) && $ value ) && !$ value instanceof \__PHP_Incomplete_Class && !\is_resource ($ value )) {
37
+ return var_export ($ value , true );
34
38
}
39
+
35
40
$ objectsPool = new \SplObjectStorage ();
36
- $ value = array ($ value );
37
- $ objectsCount = self ::doMarshall ($ value , $ objectsPool );
41
+ $ refsPool = array ();
42
+ $ objectsCount = 0 ;
43
+
44
+ try {
45
+ $ value = Marshaller::marshall (array ($ value ), $ objectsPool , $ refsPool , $ objectsCount , $ isStaticValue )[0 ];
46
+ } finally {
47
+ $ references = array ();
48
+ foreach ($ refsPool as $ i => $ v ) {
49
+ $ v [0 ] = $ v [1 ];
50
+ $ references [1 + $ i ] = $ v [2 ];
51
+ }
52
+ }
53
+
54
+ if ($ isStaticValue ) {
55
+ return var_export ($ value , true );
56
+ }
38
57
39
58
$ classes = array ();
40
59
$ values = array ();
@@ -46,6 +65,7 @@ public static function marshall($value, int &$objectsCount)
46
65
}
47
66
}
48
67
ksort ($ wakeups );
68
+
49
69
$ properties = array ();
50
70
foreach ($ values as $ i => $ vars ) {
51
71
foreach ($ vars as $ class => $ values ) {
@@ -54,131 +74,14 @@ public static function marshall($value, int &$objectsCount)
54
74
}
55
75
}
56
76
}
57
- if (!$ classes ) {
58
- return $ value [0 ];
59
- }
60
-
61
- return new Configurator (new Registry ($ classes ), $ properties , $ value [0 ], $ wakeups );
62
- }
63
-
64
- public static function optimize (string $ exportedValue )
65
- {
66
- return preg_replace (sprintf ("{%s::__set_state\(array\(\s++'0' => (\d+),\s++\)\)} " , preg_quote (Reference::class)), Registry::class.'::$objects[$1] ' , $ exportedValue );
67
- }
68
-
69
- private static function doMarshall (array &$ array , \SplObjectStorage $ objectsPool ): int
70
- {
71
- $ objectsCount = 0 ;
72
-
73
- foreach ($ array as &$ value ) {
74
- if (\is_array ($ value ) && $ value ) {
75
- $ objectsCount += self ::doMarshall ($ value , $ objectsPool );
76
- }
77
- if (!\is_object ($ value )) {
78
- continue ;
79
- }
80
- if (isset ($ objectsPool [$ value ])) {
81
- ++$ objectsCount ;
82
- $ value = new Reference ($ objectsPool [$ value ][0 ]);
83
- continue ;
84
- }
85
- $ class = \get_class ($ value );
86
- $ properties = array ();
87
- $ sleep = null ;
88
- $ arrayValue = (array ) $ value ;
89
- $ proto = (Registry::$ reflectors [$ class ] ?? Registry::getClassReflector ($ class ))->newInstanceWithoutConstructor ();
90
77
91
- if ($ value instanceof \ArrayIterator || $ value instanceof \ArrayObject) {
92
- // ArrayIterator and ArrayObject need special care because their "flags"
93
- // option changes the behavior of the (array) casting operator.
94
- $ reflector = $ value instanceof \ArrayIterator ? 'ArrayIterator ' : 'ArrayObject ' ;
95
- $ reflector = Registry::$ reflectors [$ reflector ] ?? Registry::getClassReflector ($ reflector );
78
+ $ value = new Configurator ($ classes ? new Registry ($ classes ) : null , $ references ? new Values ($ references ) : null , $ properties , $ value , $ wakeups );
79
+ $ value = var_export ($ value , true );
96
80
97
- $ properties = array (
98
- $ arrayValue ,
99
- $ reflector ->getMethod ('getFlags ' )->invoke ($ value ),
100
- $ value instanceof \ArrayObject ? $ reflector ->getMethod ('getIteratorClass ' )->invoke ($ value ) : 'ArrayIterator ' ,
101
- );
102
-
103
- $ reflector = $ reflector ->getMethod ('setFlags ' );
104
- $ reflector ->invoke ($ proto , \ArrayObject::STD_PROP_LIST );
105
-
106
- if ($ properties [1 ] & \ArrayObject::STD_PROP_LIST ) {
107
- $ reflector ->invoke ($ value , 0 );
108
- $ properties [0 ] = (array ) $ value ;
109
- } else {
110
- $ reflector ->invoke ($ value , \ArrayObject::STD_PROP_LIST );
111
- $ arrayValue = (array ) $ value ;
112
- }
113
- $ reflector ->invoke ($ value , $ properties [1 ]);
114
-
115
- if (array (array (), 0 , 'ArrayIterator ' ) === $ properties ) {
116
- $ properties = array ();
117
- } else {
118
- if ('ArrayIterator ' === $ properties [2 ]) {
119
- unset($ properties [2 ]);
120
- }
121
- $ properties = array ($ reflector ->class => array ("\0" => $ properties ));
122
- }
123
- } elseif ($ value instanceof \SplObjectStorage) {
124
- foreach (clone $ value as $ v ) {
125
- $ properties [] = $ v ;
126
- $ properties [] = $ value [$ v ];
127
- }
128
- $ properties = array ('SplObjectStorage ' => array ("\0" => $ properties ));
129
- } elseif ($ value instanceof \Serializable) {
130
- ++$ objectsCount ;
131
- $ objectsPool [$ value ] = array ($ id = \count ($ objectsPool ), serialize ($ value ), array (), 0 );
132
- $ value = new Reference ($ id );
133
- continue ;
134
- }
135
-
136
- if (\method_exists ($ class , '__sleep ' )) {
137
- if (!\is_array ($ sleep = $ value ->__sleep ())) {
138
- trigger_error ('serialize(): __sleep should return an array only containing the names of instance-variables to serialize ' , E_USER_NOTICE );
139
- $ value = null ;
140
- continue ;
141
- }
142
- $ sleep = array_flip ($ sleep );
143
- }
144
-
145
- $ proto = (array ) $ proto ;
146
-
147
- foreach ($ arrayValue as $ name => $ v ) {
148
- $ k = (string ) $ name ;
149
- if ('' === $ k || "\0" !== $ k [0 ]) {
150
- $ c = $ class ;
151
- } elseif ('* ' === $ k [1 ]) {
152
- $ c = $ class ;
153
- $ k = substr ($ k , 3 );
154
- } else {
155
- $ i = strpos ($ k , "\0" , 2 );
156
- $ c = substr ($ k , 1 , $ i - 1 );
157
- $ k = substr ($ k , 1 + $ i );
158
- }
159
- if (null === $ sleep ) {
160
- $ properties [$ c ][$ k ] = $ v ;
161
- } elseif (isset ($ sleep [$ k ]) && $ c === $ class ) {
162
- $ properties [$ c ][$ k ] = $ v ;
163
- unset($ sleep [$ k ]);
164
- }
165
- if (\array_key_exists ($ name , $ proto ) && $ proto [$ name ] === $ v ) {
166
- unset($ properties [$ c ][$ k ]);
167
- }
168
- }
169
- if ($ sleep ) {
170
- foreach ($ sleep as $ k => $ v ) {
171
- trigger_error (sprintf ('serialize(): "%s" returned as member variable from __sleep() but does not exist ' , $ k ), E_USER_NOTICE );
172
- }
173
- }
174
-
175
- $ objectsPool [$ value ] = array ($ id = \count ($ objectsPool ));
176
- $ objectsCount += 1 + self ::doMarshall ($ properties , $ objectsPool );
177
- $ objectsPool [$ value ] = array ($ id , $ class , $ properties , \method_exists ($ class , '__wakeup ' ) ? $ objectsCount : 0 );
178
-
179
- $ value = new Reference ($ id );
180
- }
81
+ $ regexp = sprintf ("{%s::__set_state\(array\(\s++'id' => %%s(\d+),\s++\)\)} " , preg_quote (Reference::class));
82
+ $ value = preg_replace (sprintf ($ regexp , '' ), Registry::class.'::$objects[$1] ' , $ value );
83
+ $ value = preg_replace (sprintf ($ regexp , '- ' ), '& ' .Registry::class.'::$references[$1] ' , $ value );
181
84
182
- return $ objectsCount ;
85
+ return $ value ;
183
86
}
184
87
}
0 commit comments