Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cefa1b5

Browse files
committed
[Debug] moved special fatal error handlers to their own classes
1 parent 53ab284 commit cefa1b5

File tree

6 files changed

+297
-209
lines changed

6 files changed

+297
-209
lines changed

src/Symfony/Component/Debug/ErrorHandler.php

Lines changed: 13 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,10 @@
1212
namespace Symfony\Component\Debug;
1313

1414
use Psr\Log\LoggerInterface;
15-
use Symfony\Component\Debug\Exception\ClassNotFoundException;
1615
use Symfony\Component\Debug\Exception\ContextErrorException;
1716
use Symfony\Component\Debug\Exception\FatalErrorException;
18-
use Symfony\Component\Debug\Exception\UndefinedFunctionException;
19-
use Composer\Autoload\ClassLoader as ComposerClassLoader;
20-
use Symfony\Component\ClassLoader as SymfonyClassLoader;
21-
use Symfony\Component\ClassLoader\DebugClassLoader;
17+
use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
18+
use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
2219

2320
/**
2421
* ErrorHandler.
@@ -160,6 +157,14 @@ public function handleFatal()
160157
$this->handleFatalError($error);
161158
}
162159

160+
public function getFatalErrorHandlers()
161+
{
162+
return array(
163+
new UndefinedFunctionFatalErrorHandler(),
164+
new ClassNotFoundFatalErrorHandler(),
165+
);
166+
}
167+
163168
private function handleFatalError($error)
164169
{
165170
// get current exception handler
@@ -171,210 +176,11 @@ private function handleFatalError($error)
171176
$message = sprintf('%s: %s in %s line %d', $level, $error['message'], $error['file'], $error['line']);
172177
$exception = new FatalErrorException($message, 0, $error['type'], $error['file'], $error['line']);
173178

174-
if ($ex = $this->handleUndefinedFunctionError($error, $exception)) {
175-
return $exceptionHandler[0]->handle($ex);
176-
}
177-
178-
if ($ex = $this->handleClassNotFoundError($error, $exception)) {
179-
return $exceptionHandler[0]->handle($ex);
180-
}
181-
182-
$exceptionHandler[0]->handle($exception);
183-
}
184-
}
185-
186-
private function handleUndefinedFunctionError($error, $exception)
187-
{
188-
$messageLen = strlen($error['message']);
189-
$notFoundSuffix = '()';
190-
$notFoundSuffixLen = strlen($notFoundSuffix);
191-
if ($notFoundSuffixLen > $messageLen) {
192-
return;
193-
}
194-
195-
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
196-
return;
197-
}
198-
199-
$prefix = 'Call to undefined function ';
200-
$prefixLen = strlen($prefix);
201-
if (0 !== strpos($error['message'], $prefix)) {
202-
return;
203-
}
204-
205-
$fullyQualifiedFunctionName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
206-
if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedFunctionName, '\\')) {
207-
$functionName = substr($fullyQualifiedFunctionName, $namespaceSeparatorIndex + 1);
208-
$namespacePrefix = substr($fullyQualifiedFunctionName, 0, $namespaceSeparatorIndex);
209-
$message = sprintf(
210-
'Attempted to call function "%s" from namespace "%s" in %s line %d.',
211-
$functionName,
212-
$namespacePrefix,
213-
$error['file'],
214-
$error['line']
215-
);
216-
} else {
217-
$functionName = $fullyQualifiedFunctionName;
218-
$message = sprintf(
219-
'Attempted to call function "%s" from the global namespace in %s line %d.',
220-
$functionName,
221-
$error['file'],
222-
$error['line']
223-
);
224-
}
225-
226-
$candidates = array();
227-
foreach (get_defined_functions() as $type => $definedFunctionNames) {
228-
foreach ($definedFunctionNames as $definedFunctionName) {
229-
if (false !== $namespaceSeparatorIndex = strrpos($definedFunctionName, '\\')) {
230-
$definedFunctionNameBasename = substr($definedFunctionName, $namespaceSeparatorIndex + 1);
231-
} else {
232-
$definedFunctionNameBasename = $definedFunctionName;
233-
}
234-
235-
if ($definedFunctionNameBasename === $functionName) {
236-
$candidates[] = '\\'.$definedFunctionName;
237-
}
238-
}
239-
}
240-
241-
if ($candidates) {
242-
$message .= ' Did you mean to call: '.implode(', ', array_map(function ($val) {
243-
return '"'.$val.'"';
244-
}, $candidates)).'?';
245-
}
246-
247-
return new UndefinedFunctionException($message, $exception);
248-
}
249-
250-
private function handleClassNotFoundError($error, $exception)
251-
{
252-
$messageLen = strlen($error['message']);
253-
$notFoundSuffix = '" not found';
254-
$notFoundSuffixLen = strlen($notFoundSuffix);
255-
if ($notFoundSuffixLen > $messageLen) {
256-
return;
257-
}
258-
259-
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
260-
return;
261-
}
262-
263-
foreach (array('class', 'interface', 'trait') as $typeName) {
264-
$prefix = ucfirst($typeName).' "';
265-
$prefixLen = strlen($prefix);
266-
if (0 !== strpos($error['message'], $prefix)) {
267-
continue;
268-
}
269-
270-
$fullyQualifiedClassName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
271-
if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) {
272-
$className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1);
273-
$namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex);
274-
$message = sprintf(
275-
'Attempted to load %s "%s" from namespace "%s" in %s line %d. Do you need to "use" it from another namespace?',
276-
$typeName,
277-
$className,
278-
$namespacePrefix,
279-
$error['file'],
280-
$error['line']
281-
);
282-
} else {
283-
$className = $fullyQualifiedClassName;
284-
$message = sprintf(
285-
'Attempted to load %s "%s" from the global namespace in %s line %d. Did you forget a use statement for this %s?',
286-
$typeName,
287-
$className,
288-
$error['file'],
289-
$error['line'],
290-
$typeName
291-
);
292-
}
293-
294-
if ($classes = $this->getClassCandidates($className)) {
295-
$message .= sprintf(' Perhaps you need to add a use statement for one of the following class: %s.', implode(', ', $classes));
296-
}
297-
298-
return new ClassNotFoundException($message, $exception);
299-
}
300-
}
301-
302-
/**
303-
* Tries to guess the full namespace for a given class name.
304-
*
305-
* By default, it looks for PSR-0 classes registered via a Symfony or a Composer
306-
* autoloader (that should cover all common cases).
307-
*
308-
* @param string $class A class name (without its namespace)
309-
*
310-
* @return array An array of possible fully qualified class names
311-
*/
312-
private function getClassCandidates($class)
313-
{
314-
if (!is_array($functions = spl_autoload_functions())) {
315-
return array();
316-
}
317-
318-
// find Symfony and Composer autoloaders
319-
$classes = array();
320-
foreach ($functions as $function) {
321-
if (!is_array($function)) {
322-
continue;
323-
}
324-
325-
// get class loaders wrapped by DebugClassLoader
326-
if ($function[0] instanceof DebugClassLoader && method_exists($function[0], 'getClassLoader')) {
327-
$function[0] = $function[0]->getClassLoader();
328-
}
329-
330-
if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader) {
331-
foreach ($function[0]->getPrefixes() as $paths) {
332-
foreach ($paths as $path) {
333-
$classes = array_merge($classes, $this->findClassInPath($function[0], $path, $class));
334-
}
179+
foreach ($this->getFatalErrorHandlers() as $handler) {
180+
if ($ex = $handler->handleError($error, $exception)) {
181+
return $exceptionHandler[0]->handle($ex);
335182
}
336183
}
337184
}
338-
339-
return $classes;
340-
}
341-
342-
private function findClassInPath($loader, $path, $class)
343-
{
344-
if (!$path = realpath($path)) {
345-
continue;
346-
}
347-
348-
$classes = array();
349-
$filename = $class.'.php';
350-
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
351-
if ($filename == $file->getFileName() && $class = $this->convertFileToClass($loader, $path, $file->getPathName())) {
352-
$classes[] = $class;
353-
}
354-
}
355-
356-
return $classes;
357-
}
358-
359-
private function convertFileToClass($loader, $path, $file)
360-
{
361-
// We cannot use the autoloader here as most of them use require; but if the class
362-
// is not found, the new autoloader call will require the file again leading to a
363-
// "cannot redeclare class" error.
364-
require_once $file;
365-
366-
$file = str_replace(array($path.'/', '.php'), array('', ''), $file);
367-
368-
// is it a namespaced class?
369-
$class = str_replace('/', '\\', $file);
370-
if (class_exists($class, false) || interface_exists($class, false) || (function_exists('trait_exists') && trait_exists($class, false))) {
371-
return $class;
372-
}
373-
374-
// is it a PEAR-like class name instead?
375-
$class = str_replace('/', '_', $file);
376-
if (class_exists($class, false) || interface_exists($class, false) || (function_exists('trait_exists') && trait_exists($class, false))) {
377-
return $class;
378-
}
379185
}
380186
}

src/Symfony/Component/Debug/Exception/ClassNotFoundException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*
1717
* @author Konstanton Myakshin <[email protected]>
1818
*/
19-
class ClassNotFoundException extends \ErrorException
19+
class ClassNotFoundException extends FatalErrorException
2020
{
2121
public function __construct($message, \ErrorException $previous)
2222
{

src/Symfony/Component/Debug/Exception/UndefinedFunctionException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*
1717
* @author Konstanton Myakshin <[email protected]>
1818
*/
19-
class UndefinedFunctionException extends \ErrorException
19+
class UndefinedFunctionException extends FatalErrorException
2020
{
2121
public function __construct($message, \ErrorException $previous)
2222
{

0 commit comments

Comments
 (0)