@@ -41,6 +41,8 @@ class ExceptionCaster
4141 E_STRICT => 'E_STRICT ' ,
4242 );
4343
44+ private static $ framesCache = array ();
45+
4446 public static function castError (\Error $ e , array $ a , Stub $ stub , $ isNested , $ filter = 0 )
4547 {
4648 return self ::filterExceptionArray ($ stub ->class , $ a , "\0Error \0" , $ filter );
@@ -142,43 +144,52 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $is
142144 $ prefix = Caster::PREFIX_VIRTUAL ;
143145
144146 if (isset ($ f ['file ' ], $ f ['line ' ])) {
145- if (preg_match ('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\) \'d code|runtime-created function)$/ ' , $ f ['file ' ], $ match )) {
146- $ f ['file ' ] = substr ($ f ['file ' ], 0 , -strlen ($ match [0 ]));
147- $ f ['line ' ] = (int ) $ match [1 ];
148- }
149- $ caller = isset ($ f ['function ' ]) ? sprintf ('in %s() on line %d ' , (isset ($ f ['class ' ]) ? $ f ['class ' ].$ f ['type ' ] : '' ).$ f ['function ' ], $ f ['line ' ]) : null ;
150- $ src = $ f ['line ' ];
151- $ srcKey = $ f ['file ' ];
152- $ ellipsis = explode (DIRECTORY_SEPARATOR , $ srcKey );
153- $ ellipsis = 3 < count ($ ellipsis ) ? 2 + strlen (implode (array_slice ($ ellipsis , -2 ))) : 0 ;
154-
155- if (file_exists ($ f ['file ' ]) && 0 <= self ::$ srcContext ) {
156- if (!empty ($ f ['class ' ]) && is_subclass_of ($ f ['class ' ], 'Twig_Template ' ) && method_exists ($ f ['class ' ], 'getDebugInfo ' )) {
157- $ template = isset ($ f ['object ' ]) ? $ f ['object ' ] : unserialize (sprintf ('O:%d:"%s":0:{} ' , strlen ($ f ['class ' ]), $ f ['class ' ]));
158-
159- $ ellipsis = 0 ;
160- $ templateSrc = method_exists ($ template , 'getSourceContext ' ) ? $ template ->getSourceContext ()->getCode () : (method_exists ($ template , 'getSource ' ) ? $ template ->getSource () : '' );
161- $ templateInfo = $ template ->getDebugInfo ();
162- if (isset ($ templateInfo [$ f ['line ' ]])) {
163- $ templatePath = method_exists ($ template , 'getSourceContext ' ) ? $ template ->getSourceContext ()->getPath () : null ;
164-
165- if ($ templateSrc ) {
166- $ templateSrc = explode ("\n" , $ templateSrc );
167- $ src = self ::extractSource ($ templateSrc , $ templateInfo [$ f ['line ' ]], self ::$ srcContext , $ caller , 'twig ' , $ templatePath );
168- $ srcKey = ($ templatePath ?: $ template ->getTemplateName ()).': ' .$ templateInfo [$ f ['line ' ]];
147+ $ cacheKey = $ f ;
148+ unset($ cacheKey ['object ' ], $ cacheKey ['args ' ]);
149+ $ cacheKey [] = self ::$ srcContext ;
150+ $ cacheKey = implode ('- ' , $ cacheKey );
151+
152+ if (isset (self ::$ framesCache [$ cacheKey ])) {
153+ $ a [$ prefix .'src ' ] = self ::$ framesCache [$ cacheKey ];
154+ } else {
155+ if (preg_match ('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\) \'d code|runtime-created function)$/ ' , $ f ['file ' ], $ match )) {
156+ $ f ['file ' ] = substr ($ f ['file ' ], 0 , -strlen ($ match [0 ]));
157+ $ f ['line ' ] = (int ) $ match [1 ];
158+ }
159+ $ caller = isset ($ f ['function ' ]) ? sprintf ('in %s() on line %d ' , (isset ($ f ['class ' ]) ? $ f ['class ' ].$ f ['type ' ] : '' ).$ f ['function ' ], $ f ['line ' ]) : null ;
160+ $ src = $ f ['line ' ];
161+ $ srcKey = $ f ['file ' ];
162+ $ ellipsis = explode (DIRECTORY_SEPARATOR , $ srcKey );
163+ $ ellipsis = 3 < count ($ ellipsis ) ? 2 + strlen (implode (array_slice ($ ellipsis , -2 ))) : 0 ;
164+
165+ if (file_exists ($ f ['file ' ]) && 0 <= self ::$ srcContext ) {
166+ if (!empty ($ f ['class ' ]) && is_subclass_of ($ f ['class ' ], 'Twig_Template ' ) && method_exists ($ f ['class ' ], 'getDebugInfo ' )) {
167+ $ template = isset ($ f ['object ' ]) ? $ f ['object ' ] : unserialize (sprintf ('O:%d:"%s":0:{} ' , strlen ($ f ['class ' ]), $ f ['class ' ]));
168+
169+ $ ellipsis = 0 ;
170+ $ templateSrc = method_exists ($ template , 'getSourceContext ' ) ? $ template ->getSourceContext ()->getCode () : (method_exists ($ template , 'getSource ' ) ? $ template ->getSource () : '' );
171+ $ templateInfo = $ template ->getDebugInfo ();
172+ if (isset ($ templateInfo [$ f ['line ' ]])) {
173+ if (!method_exists ($ template , 'getSourceContext ' ) || !file_exists ($ templatePath = $ template ->getSourceContext ()->getPath ())) {
174+ $ templatePath = null ;
175+ }
176+ if ($ templateSrc ) {
177+ $ src = self ::extractSource ($ templateSrc , $ templateInfo [$ f ['line ' ]], self ::$ srcContext , $ caller , 'twig ' , $ templatePath );
178+ $ srcKey = ($ templatePath ?: $ template ->getTemplateName ()).': ' .$ templateInfo [$ f ['line ' ]];
179+ }
169180 }
170181 }
171- }
172- if ( $ srcKey == $ f ['file ' ]) {
173- $ src = self :: extractSource ( explode ( "\n" , file_get_contents ( $ f [ ' file ' ])), $ f [ ' line ' ], self :: $ srcContext , $ caller , ' php ' , $ f ['file ' ]) ;
174- $ srcKey .= ' : ' . $ f [ ' line ' ];
175- if ( $ ellipsis) {
176- $ ellipsis += 1 + strlen ( $ f [ ' line ' ]);
182+ if ( $ srcKey == $ f [ ' file ' ]) {
183+ $ src = self :: extractSource ( file_get_contents ( $ f ['file ' ]), $ f [ ' line ' ], self :: $ srcContext , $ caller , ' php ' , $ f [ ' file ' ]);
184+ $ srcKey .= ' : ' . $ f ['line ' ] ;
185+ if ( $ ellipsis ) {
186+ $ ellipsis += 1 + strlen ( $ f [ ' line ' ]);
187+ }
177188 }
178189 }
190+ $ srcAttr = $ ellipsis ? 'ellipsis= ' .$ ellipsis : '' ;
191+ self ::$ framesCache [$ cacheKey ] = $ a [$ prefix .'src ' ] = new EnumStub (array ("\0~ $ srcAttr \0$ srcKey " => $ src ));
179192 }
180- $ srcAttr = $ ellipsis ? 'ellipsis= ' .$ ellipsis : '' ;
181- $ a [$ prefix .'src ' ] = new EnumStub (array ("\0~ $ srcAttr \0$ srcKey " => $ src ));
182193 }
183194
184195 unset($ a [$ prefix .'args ' ], $ a [$ prefix .'line ' ], $ a [$ prefix .'file ' ]);
@@ -232,14 +243,16 @@ private static function traceUnshift(&$trace, $class, $file, $line)
232243 ));
233244 }
234245
235- private static function extractSource (array $ srcArray , $ line , $ srcContext , $ title , $ lang , $ file = null )
246+ private static function extractSource ($ srcLines , $ line , $ srcContext , $ title , $ lang , $ file = null )
236247 {
248+ $ srcLines = explode ("\n" , $ srcLines );
237249 $ src = array ();
238250
239251 for ($ i = $ line - 1 - $ srcContext ; $ i <= $ line - 1 + $ srcContext ; ++$ i ) {
240- $ src [] = (isset ($ srcArray [$ i ]) ? $ srcArray [$ i ] : '' )."\n" ;
252+ $ src [] = (isset ($ srcLines [$ i ]) ? $ srcLines [$ i ] : '' )."\n" ;
241253 }
242254
255+ $ srcLines = array ();
243256 $ ltrim = 0 ;
244257 do {
245258 $ pad = null ;
@@ -257,7 +270,6 @@ private static function extractSource(array $srcArray, $line, $srcContext, $titl
257270 } while (0 > $ i && null !== $ pad );
258271
259272 --$ ltrim ;
260- $ srcArray = array ();
261273
262274 foreach ($ src as $ i => $ c ) {
263275 if ($ ltrim ) {
@@ -274,9 +286,9 @@ private static function extractSource(array $srcArray, $line, $srcContext, $titl
274286 }
275287 }
276288 $ c ->attr ['lang ' ] = $ lang ;
277- $ srcArray [sprintf ("\0~%d \0" , $ i + $ line - $ srcContext )] = $ c ;
289+ $ srcLines [sprintf ("\0~%d \0" , $ i + $ line - $ srcContext )] = $ c ;
278290 }
279291
280- return new EnumStub ($ srcArray );
292+ return new EnumStub ($ srcLines );
281293 }
282294}
0 commit comments