1212namespace Symfony \Component \Cache \Marshaller ;
1313
1414use Symfony \Component \Cache \Marshaller \PhpMarshaller \Configurator ;
15+ use Symfony \Component \Cache \Marshaller \PhpMarshaller \Marshaller ;
1516use Symfony \Component \Cache \Marshaller \PhpMarshaller \Reference ;
1617use Symfony \Component \Cache \Marshaller \PhpMarshaller \Registry ;
18+ use Symfony \Component \Cache \Marshaller \PhpMarshaller \Values ;
1719
1820/**
1921 * @author Nicolas Grekas <p@tchwork.com>
2729 */
2830class PhpMarshaller
2931{
30- public static function marshall ($ value , int &$ objectsCount )
32+ public static function marshall ($ value , bool &$ isStaticValue = null ): string
3133 {
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 );
3438 }
39+
3540 $ 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+ }
3857
3958 $ classes = array ();
4059 $ values = array ();
@@ -46,6 +65,7 @@ public static function marshall($value, int &$objectsCount)
4665 }
4766 }
4867 ksort ($ wakeups );
68+
4969 $ properties = array ();
5070 foreach ($ values as $ i => $ vars ) {
5171 foreach ($ vars as $ class => $ values ) {
@@ -54,131 +74,14 @@ public static function marshall($value, int &$objectsCount)
5474 }
5575 }
5676 }
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 ();
9077
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 );
9680
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 );
18184
182- return $ objectsCount ;
85+ return $ value ;
18386 }
18487}
0 commit comments