mirror of
https://github.com/symfony/debug.git
synced 2026-03-25 01:32:09 +01:00
Compare commits
180 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b70cfaae39 | ||
|
|
d7b459ba7b | ||
|
|
4fd77efcd4 | ||
|
|
87cecce74b | ||
|
|
c4625e7534 | ||
|
|
cbb8a5f212 | ||
|
|
d5a058ff6e | ||
|
|
d985c8546d | ||
|
|
13041d84e3 | ||
|
|
2f42aa269a | ||
|
|
34bdb1c801 | ||
|
|
d070fc2e64 | ||
|
|
0e3ca9cbde | ||
|
|
47e6788c5b | ||
|
|
a26ddce7fe | ||
|
|
a7e8068943 | ||
|
|
5d48e9c0f8 | ||
|
|
b28fd73fef | ||
|
|
c7d48cc12e | ||
|
|
63299f103f | ||
|
|
fe8838e11c | ||
|
|
fc4afe37fd | ||
|
|
1b95888cfd | ||
|
|
9cf7c2271c | ||
|
|
4486d2be5e | ||
|
|
e191af723b | ||
|
|
c32ac36516 | ||
|
|
ce92aa6388 | ||
|
|
7e7619ce57 | ||
|
|
59ef7fdee7 | ||
|
|
b74e4e0899 | ||
|
|
5555d0c0c4 | ||
|
|
0a614d393b | ||
|
|
9b1071f86e | ||
|
|
f693ba8818 | ||
|
|
6a76089f75 | ||
|
|
709ea1dc13 | ||
|
|
338c06c0dc | ||
|
|
9cca71588a | ||
|
|
7d96be3eaf | ||
|
|
0d52d1c98c | ||
|
|
4917f03992 | ||
|
|
a91a8fdd8c | ||
|
|
53f6af2805 | ||
|
|
610391bbb9 | ||
|
|
35e36287fc | ||
|
|
bc9e38887a | ||
|
|
08f0bf898f | ||
|
|
b1babdd3a2 | ||
|
|
955cfa5e94 | ||
|
|
fa4249925a | ||
|
|
823c28fafd | ||
|
|
05e858fda6 | ||
|
|
253f4fd5f6 | ||
|
|
603b95dda8 | ||
|
|
7f2d1c75f6 | ||
|
|
546db6f2bf | ||
|
|
ff9e8cb401 | ||
|
|
e46133c70d | ||
|
|
6bedafa288 | ||
|
|
7f4478ce1c | ||
|
|
c617cfc32e | ||
|
|
526150f1a8 | ||
|
|
4790d01677 | ||
|
|
32533da9ec | ||
|
|
b8c44f3906 | ||
|
|
5f44cab999 | ||
|
|
79c3d84f0b | ||
|
|
c6d3f008f5 | ||
|
|
c5ba0ded9d | ||
|
|
22c18d44e7 | ||
|
|
79b7f987a6 | ||
|
|
12370d9f98 | ||
|
|
0972e3f262 | ||
|
|
2113921b59 | ||
|
|
177a0b9b35 | ||
|
|
93e1e7c901 | ||
|
|
b16f5f7634 | ||
|
|
4f43301e60 | ||
|
|
1086f33dba | ||
|
|
543deab3ff | ||
|
|
68c27a1736 | ||
|
|
7f065aa0af | ||
|
|
8895e0f1a9 | ||
|
|
35b6ef09dc | ||
|
|
d0cddb9f2a | ||
|
|
c573a9f2a1 | ||
|
|
fb2001e5d8 | ||
|
|
d120b899c0 | ||
|
|
ab84a63772 | ||
|
|
e72a0340dc | ||
|
|
38fdc933c7 | ||
|
|
24b7bbfc7c | ||
|
|
b25b18421a | ||
|
|
74557880e2 | ||
|
|
def1666122 | ||
|
|
9ebd154442 | ||
|
|
2854347f27 | ||
|
|
a0a29e9867 | ||
|
|
271c75c24d | ||
|
|
723643a94b | ||
|
|
5f49adc996 | ||
|
|
08bf2c53db | ||
|
|
f0546da70c | ||
|
|
147025beaf | ||
|
|
88e1bd3ad2 | ||
|
|
d295479508 | ||
|
|
d2d11379b5 | ||
|
|
44c8fb3f90 | ||
|
|
eb95d9ce8f | ||
|
|
eaaec993ca | ||
|
|
e12a6f1168 | ||
|
|
34d945c4eb | ||
|
|
1407679206 | ||
|
|
c0a3a6b4f2 | ||
|
|
820b5ae4c3 | ||
|
|
3bea0cdeb5 | ||
|
|
2827a6e8c2 | ||
|
|
9c5b622f5a | ||
|
|
33f6f36c28 | ||
|
|
8beb24eec7 | ||
|
|
f43bc2e05d | ||
|
|
084d804fe3 | ||
|
|
efc9656dcb | ||
|
|
f45a908634 | ||
|
|
50bda5b4b8 | ||
|
|
f28018d622 | ||
|
|
b7190d5620 | ||
|
|
0920d5f066 | ||
|
|
3be4178b91 | ||
|
|
c9fcef80c3 | ||
|
|
e06181ae56 | ||
|
|
97592888b9 | ||
|
|
7c13ae8ce1 | ||
|
|
ba7276868c | ||
|
|
236ca98a42 | ||
|
|
0946243775 | ||
|
|
e1ce6a4ded | ||
|
|
296d63b9b2 | ||
|
|
ee6732177c | ||
|
|
18ac7ae10d | ||
|
|
63b85a9684 | ||
|
|
9d40ad561e | ||
|
|
bcfd02728d | ||
|
|
4e323c3ebd | ||
|
|
6694bfe6ac | ||
|
|
e9c5048284 | ||
|
|
8d4977c296 | ||
|
|
8470d77011 | ||
|
|
2662c21dea | ||
|
|
46cf671348 | ||
|
|
0f82f184dd | ||
|
|
ef5f19a7a6 | ||
|
|
20bb3a9837 | ||
|
|
91dc1c8129 | ||
|
|
627c397b80 | ||
|
|
2a237220d7 | ||
|
|
60a2e6484d | ||
|
|
fd6d8ec34d | ||
|
|
a40c94b3ec | ||
|
|
9e74640b1b | ||
|
|
3670057096 | ||
|
|
105f6a2106 | ||
|
|
897f7e81a6 | ||
|
|
f154f7d131 | ||
|
|
6a980cb6c9 | ||
|
|
84a2c430d9 | ||
|
|
55f724564d | ||
|
|
8dfba97c33 | ||
|
|
ae6304238d | ||
|
|
eff22f5888 | ||
|
|
e990e0b4f5 | ||
|
|
88d66d1f16 | ||
|
|
7a0d1faf0e | ||
|
|
37dcd47814 | ||
|
|
10ceed2518 | ||
|
|
fa5b1b68e9 | ||
|
|
e45647910b | ||
|
|
a6541af09b | ||
|
|
342af93b6b |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,6 +1,16 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
* deprecated `ErrorHandler::stackErrors()` and `ErrorHandler::unstackErrors()`
|
||||
|
||||
3.3.0
|
||||
-----
|
||||
|
||||
* deprecated the `ContextErrorException` class: use \ErrorException directly now
|
||||
|
||||
3.2.0
|
||||
-----
|
||||
|
||||
|
||||
@@ -23,10 +23,7 @@ class Debug
|
||||
/**
|
||||
* Enables the debug tools.
|
||||
*
|
||||
* This method registers an error handler and an exception handler.
|
||||
*
|
||||
* If the Symfony ClassLoader component is available, a special
|
||||
* class loader is also registered.
|
||||
* This method registers an error handler, an exception handler and a special class loader.
|
||||
*
|
||||
* @param int $errorReportingLevel The level of error reporting you want
|
||||
* @param bool $displayErrors Whether to display errors (for development) or just log them (for production)
|
||||
@@ -45,7 +42,7 @@ class Debug
|
||||
error_reporting(E_ALL);
|
||||
}
|
||||
|
||||
if ('cli' !== PHP_SAPI) {
|
||||
if (!\in_array(\PHP_SAPI, array('cli', 'phpdbg'), true)) {
|
||||
ini_set('display_errors', 0);
|
||||
ExceptionHandler::register();
|
||||
} elseif ($displayErrors && (!ini_get('log_errors') || ini_get('error_log'))) {
|
||||
|
||||
@@ -26,24 +26,25 @@ class DebugClassLoader
|
||||
{
|
||||
private $classLoader;
|
||||
private $isFinder;
|
||||
private $loaded = array();
|
||||
private static $caseCheck;
|
||||
private static $checkedClasses = array();
|
||||
private static $final = array();
|
||||
private static $finalMethods = array();
|
||||
private static $deprecated = array();
|
||||
private static $php7Reserved = array('int', 'float', 'bool', 'string', 'true', 'false', 'null');
|
||||
private static $internal = array();
|
||||
private static $internalMethods = array();
|
||||
private static $php7Reserved = array('int' => 1, 'float' => 1, 'bool' => 1, 'string' => 1, 'true' => 1, 'false' => 1, 'null' => 1);
|
||||
private static $darwinCache = array('/' => array('/', array()));
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param callable $classLoader A class loader
|
||||
*/
|
||||
public function __construct(callable $classLoader)
|
||||
{
|
||||
$this->classLoader = $classLoader;
|
||||
$this->isFinder = is_array($classLoader) && method_exists($classLoader[0], 'findFile');
|
||||
$this->isFinder = \is_array($classLoader) && method_exists($classLoader[0], 'findFile');
|
||||
|
||||
if (!isset(self::$caseCheck)) {
|
||||
$file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), DIRECTORY_SEPARATOR);
|
||||
$i = strrpos($file, DIRECTORY_SEPARATOR);
|
||||
$file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), \DIRECTORY_SEPARATOR);
|
||||
$i = strrpos($file, \DIRECTORY_SEPARATOR);
|
||||
$dir = substr($file, 0, 1 + $i);
|
||||
$file = substr($file, 1 + $i);
|
||||
$test = strtoupper($file) === $file ? strtolower($file) : strtoupper($file);
|
||||
@@ -52,7 +53,7 @@ class DebugClassLoader
|
||||
if (false === $test || false === $i) {
|
||||
// filesystem is case sensitive
|
||||
self::$caseCheck = 0;
|
||||
} elseif (substr($test, -strlen($file)) === $file) {
|
||||
} elseif (substr($test, -\strlen($file)) === $file) {
|
||||
// filesystem is case insensitive and realpath() normalizes the case of characters
|
||||
self::$caseCheck = 1;
|
||||
} elseif (false !== stripos(PHP_OS, 'darwin')) {
|
||||
@@ -84,7 +85,7 @@ class DebugClassLoader
|
||||
class_exists('Symfony\Component\Debug\ErrorHandler');
|
||||
class_exists('Psr\Log\LogLevel');
|
||||
|
||||
if (!is_array($functions = spl_autoload_functions())) {
|
||||
if (!\is_array($functions = spl_autoload_functions())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -93,7 +94,7 @@ class DebugClassLoader
|
||||
}
|
||||
|
||||
foreach ($functions as $function) {
|
||||
if (!is_array($function) || !$function[0] instanceof self) {
|
||||
if (!\is_array($function) || !$function[0] instanceof self) {
|
||||
$function = array(new static($function), 'loadClass');
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ class DebugClassLoader
|
||||
*/
|
||||
public static function disable()
|
||||
{
|
||||
if (!is_array($functions = spl_autoload_functions())) {
|
||||
if (!\is_array($functions = spl_autoload_functions())) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,7 +116,7 @@ class DebugClassLoader
|
||||
}
|
||||
|
||||
foreach ($functions as $function) {
|
||||
if (is_array($function) && $function[0] instanceof self) {
|
||||
if (\is_array($function) && $function[0] instanceof self) {
|
||||
$function = $function[0]->getClassLoader();
|
||||
}
|
||||
|
||||
@@ -128,187 +129,306 @@ class DebugClassLoader
|
||||
*
|
||||
* @param string $class The name of the class
|
||||
*
|
||||
* @return bool|null True, if loaded
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function loadClass($class)
|
||||
{
|
||||
ErrorHandler::stackErrors();
|
||||
$e = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
|
||||
|
||||
try {
|
||||
if ($this->isFinder) {
|
||||
if ($file = $this->classLoader[0]->findFile($class)) {
|
||||
require_once $file;
|
||||
if ($this->isFinder && !isset($this->loaded[$class])) {
|
||||
$this->loaded[$class] = true;
|
||||
if ($file = $this->classLoader[0]->findFile($class) ?: false) {
|
||||
$wasCached = \function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file);
|
||||
|
||||
require $file;
|
||||
|
||||
if ($wasCached) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
call_user_func($this->classLoader, $class);
|
||||
\call_user_func($this->classLoader, $class);
|
||||
$file = false;
|
||||
}
|
||||
} finally {
|
||||
ErrorHandler::unstackErrors();
|
||||
error_reporting($e);
|
||||
}
|
||||
|
||||
$exists = class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
|
||||
$this->checkClass($class, $file);
|
||||
}
|
||||
|
||||
if ($class && '\\' === $class[0]) {
|
||||
private function checkClass($class, $file = null)
|
||||
{
|
||||
$exists = null === $file || \class_exists($class, false) || \interface_exists($class, false) || \trait_exists($class, false);
|
||||
|
||||
if (null !== $file && $class && '\\' === $class[0]) {
|
||||
$class = substr($class, 1);
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
if (isset(self::$checkedClasses[$class])) {
|
||||
return;
|
||||
}
|
||||
self::$checkedClasses[$class] = true;
|
||||
|
||||
$refl = new \ReflectionClass($class);
|
||||
if (null === $file && $refl->isInternal()) {
|
||||
return;
|
||||
}
|
||||
$name = $refl->getName();
|
||||
|
||||
if ($name !== $class && 0 === strcasecmp($name, $class)) {
|
||||
throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: %s vs %s', $class, $name));
|
||||
if ($name !== $class && 0 === \strcasecmp($name, $class)) {
|
||||
throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: "%s" vs "%s".', $class, $name));
|
||||
}
|
||||
|
||||
if (in_array(strtolower($refl->getShortName()), self::$php7Reserved)) {
|
||||
@trigger_error(sprintf('%s uses a reserved class name (%s) that will break on PHP 7 and higher', $name, $refl->getShortName()), E_USER_DEPRECATED);
|
||||
} elseif (preg_match('#\n \* @deprecated (.*?)\r?\n \*(?: @|/$)#s', $refl->getDocComment(), $notice)) {
|
||||
self::$deprecated[$name] = preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]);
|
||||
} else {
|
||||
if (2 > $len = 1 + (strpos($name, '\\', 1 + strpos($name, '\\')) ?: strpos($name, '_'))) {
|
||||
$len = 0;
|
||||
$ns = '';
|
||||
} else {
|
||||
switch ($ns = substr($name, 0, $len)) {
|
||||
case 'Symfony\Bridge\\':
|
||||
case 'Symfony\Bundle\\':
|
||||
case 'Symfony\Component\\':
|
||||
$ns = 'Symfony\\';
|
||||
$len = strlen($ns);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$parent = get_parent_class($class);
|
||||
$deprecations = $this->checkAnnotations($refl, $name);
|
||||
|
||||
if (!$parent || strncmp($ns, $parent, $len)) {
|
||||
if ($parent && isset(self::$deprecated[$parent]) && strncmp($ns, $parent, $len)) {
|
||||
@trigger_error(sprintf('The %s class extends %s that is deprecated %s', $name, $parent, self::$deprecated[$parent]), E_USER_DEPRECATED);
|
||||
}
|
||||
if (isset(self::$php7Reserved[\strtolower($refl->getShortName())])) {
|
||||
$deprecations[] = sprintf('The "%s" class uses the reserved name "%s", it will break on PHP 7 and higher', $name, $refl->getShortName());
|
||||
}
|
||||
|
||||
$parentInterfaces = array();
|
||||
$deprecatedInterfaces = array();
|
||||
if ($parent) {
|
||||
foreach (class_implements($parent) as $interface) {
|
||||
$parentInterfaces[$interface] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($refl->getInterfaceNames() as $interface) {
|
||||
if (isset(self::$deprecated[$interface]) && strncmp($ns, $interface, $len)) {
|
||||
$deprecatedInterfaces[] = $interface;
|
||||
}
|
||||
foreach (class_implements($interface) as $interface) {
|
||||
$parentInterfaces[$interface] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($deprecatedInterfaces as $interface) {
|
||||
if (!isset($parentInterfaces[$interface])) {
|
||||
@trigger_error(sprintf('The %s %s %s that is deprecated %s', $name, $refl->isInterface() ? 'interface extends' : 'class implements', $interface, self::$deprecated[$interface]), E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($deprecations as $message) {
|
||||
@trigger_error($message, E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
if ($file) {
|
||||
if (!$exists) {
|
||||
if (false !== strpos($class, '/')) {
|
||||
throw new \RuntimeException(sprintf('Trying to autoload a class with an invalid name "%s". Be careful that the namespace separator is "\" in PHP, not "/".', $class));
|
||||
}
|
||||
if (!$file) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file));
|
||||
}
|
||||
if (self::$caseCheck) {
|
||||
$real = explode('\\', $class.strrchr($file, '.'));
|
||||
$tail = explode(DIRECTORY_SEPARATOR, str_replace('/', DIRECTORY_SEPARATOR, $file));
|
||||
|
||||
$i = count($tail) - 1;
|
||||
$j = count($real) - 1;
|
||||
|
||||
while (isset($tail[$i], $real[$j]) && $tail[$i] === $real[$j]) {
|
||||
--$i;
|
||||
--$j;
|
||||
}
|
||||
|
||||
array_splice($tail, 0, $i + 1);
|
||||
}
|
||||
if (self::$caseCheck && $tail) {
|
||||
$tail = DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $tail);
|
||||
$tailLen = strlen($tail);
|
||||
$real = $refl->getFileName();
|
||||
|
||||
if (2 === self::$caseCheck) {
|
||||
// realpath() on MacOSX doesn't normalize the case of characters
|
||||
|
||||
$i = 1 + strrpos($real, '/');
|
||||
$file = substr($real, $i);
|
||||
$real = substr($real, 0, $i);
|
||||
|
||||
if (isset(self::$darwinCache[$real])) {
|
||||
$kDir = $real;
|
||||
} else {
|
||||
$kDir = strtolower($real);
|
||||
|
||||
if (isset(self::$darwinCache[$kDir])) {
|
||||
$real = self::$darwinCache[$kDir][0];
|
||||
} else {
|
||||
$dir = getcwd();
|
||||
chdir($real);
|
||||
$real = getcwd().'/';
|
||||
chdir($dir);
|
||||
|
||||
$dir = $real;
|
||||
$k = $kDir;
|
||||
$i = strlen($dir) - 1;
|
||||
while (!isset(self::$darwinCache[$k])) {
|
||||
self::$darwinCache[$k] = array($dir, array());
|
||||
self::$darwinCache[$dir] = &self::$darwinCache[$k];
|
||||
|
||||
while ('/' !== $dir[--$i]) {
|
||||
}
|
||||
$k = substr($k, 0, ++$i);
|
||||
$dir = substr($dir, 0, $i--);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dirFiles = self::$darwinCache[$kDir][1];
|
||||
|
||||
if (isset($dirFiles[$file])) {
|
||||
$kFile = $file;
|
||||
} else {
|
||||
$kFile = strtolower($file);
|
||||
|
||||
if (!isset($dirFiles[$kFile])) {
|
||||
foreach (scandir($real, 2) as $f) {
|
||||
if ('.' !== $f[0]) {
|
||||
$dirFiles[$f] = $f;
|
||||
if ($f === $file) {
|
||||
$kFile = $k = $file;
|
||||
} elseif ($f !== $k = strtolower($f)) {
|
||||
$dirFiles[$k] = $f;
|
||||
}
|
||||
}
|
||||
}
|
||||
self::$darwinCache[$kDir][1] = $dirFiles;
|
||||
}
|
||||
}
|
||||
|
||||
$real .= $dirFiles[$kFile];
|
||||
}
|
||||
|
||||
if (0 === substr_compare($real, $tail, -$tailLen, $tailLen, true)
|
||||
&& 0 !== substr_compare($real, $tail, -$tailLen, $tailLen, false)
|
||||
) {
|
||||
throw new \RuntimeException(sprintf('Case mismatch between class and real file names: %s vs %s in %s', substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1)));
|
||||
}
|
||||
if (!$exists) {
|
||||
if (false !== strpos($class, '/')) {
|
||||
throw new \RuntimeException(sprintf('Trying to autoload a class with an invalid name "%s". Be careful that the namespace separator is "\" in PHP, not "/".', $class));
|
||||
}
|
||||
|
||||
return true;
|
||||
throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file));
|
||||
}
|
||||
|
||||
if (self::$caseCheck && $message = $this->checkCase($refl, $file, $class)) {
|
||||
throw new \RuntimeException(sprintf('Case mismatch between class and real file names: "%s" vs "%s" in "%s".', $message[0], $message[1], $message[2]));
|
||||
}
|
||||
}
|
||||
|
||||
public function checkAnnotations(\ReflectionClass $refl, $class)
|
||||
{
|
||||
$deprecations = array();
|
||||
|
||||
// Don't trigger deprecations for classes in the same vendor
|
||||
if (2 > $len = 1 + (\strpos($class, '\\') ?: \strpos($class, '_'))) {
|
||||
$len = 0;
|
||||
$ns = '';
|
||||
} else {
|
||||
$ns = \substr($class, 0, $len);
|
||||
}
|
||||
|
||||
// Detect annotations on the class
|
||||
if (false !== $doc = $refl->getDocComment()) {
|
||||
foreach (array('final', 'deprecated', 'internal') as $annotation) {
|
||||
if (false !== \strpos($doc, $annotation) && preg_match('#\n \* @'.$annotation.'(?:( .+?)\.?)?\r?\n \*(?: @|/$)#s', $doc, $notice)) {
|
||||
self::${$annotation}[$class] = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$parent = \get_parent_class($class);
|
||||
$parentAndOwnInterfaces = $this->getOwnInterfaces($class, $parent);
|
||||
if ($parent) {
|
||||
$parentAndOwnInterfaces[$parent] = $parent;
|
||||
|
||||
if (!isset(self::$checkedClasses[$parent])) {
|
||||
$this->checkClass($parent);
|
||||
}
|
||||
|
||||
if (isset(self::$final[$parent])) {
|
||||
$deprecations[] = sprintf('The "%s" class is considered final%s. It may change without further notice as of its next major version. You should not extend it from "%s".', $parent, self::$final[$parent], $class);
|
||||
}
|
||||
}
|
||||
|
||||
// Detect if the parent is annotated
|
||||
foreach ($parentAndOwnInterfaces + \class_uses($class, false) as $use) {
|
||||
if (!isset(self::$checkedClasses[$use])) {
|
||||
$this->checkClass($use);
|
||||
}
|
||||
if (isset(self::$deprecated[$use]) && \strncmp($ns, $use, $len)) {
|
||||
$type = class_exists($class, false) ? 'class' : (interface_exists($class, false) ? 'interface' : 'trait');
|
||||
$verb = class_exists($use, false) || interface_exists($class, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses');
|
||||
|
||||
$deprecations[] = sprintf('The "%s" %s %s "%s" that is deprecated%s.', $class, $type, $verb, $use, self::$deprecated[$use]);
|
||||
}
|
||||
if (isset(self::$internal[$use]) && \strncmp($ns, $use, $len)) {
|
||||
$deprecations[] = sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $class);
|
||||
}
|
||||
}
|
||||
|
||||
if (\trait_exists($class)) {
|
||||
return $deprecations;
|
||||
}
|
||||
|
||||
// Inherit @final and @internal annotations for methods
|
||||
self::$finalMethods[$class] = array();
|
||||
self::$internalMethods[$class] = array();
|
||||
foreach ($parentAndOwnInterfaces as $use) {
|
||||
foreach (array('finalMethods', 'internalMethods') as $property) {
|
||||
if (isset(self::${$property}[$use])) {
|
||||
self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($refl->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $method) {
|
||||
if ($method->class !== $class) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($parent && isset(self::$finalMethods[$parent][$method->name])) {
|
||||
list($declaringClass, $message) = self::$finalMethods[$parent][$method->name];
|
||||
$deprecations[] = sprintf('The "%s::%s()" method is considered final%s. It may change without further notice as of its next major version. You should not extend it from "%s".', $declaringClass, $method->name, $message, $class);
|
||||
}
|
||||
|
||||
if (isset(self::$internalMethods[$class][$method->name])) {
|
||||
list($declaringClass, $message) = self::$internalMethods[$class][$method->name];
|
||||
if (\strncmp($ns, $declaringClass, $len)) {
|
||||
$deprecations[] = sprintf('The "%s::%s()" method is considered internal%s. It may change without further notice. You should not extend it from "%s".', $declaringClass, $method->name, $message, $class);
|
||||
}
|
||||
}
|
||||
|
||||
// Detect method annotations
|
||||
if (false === $doc = $method->getDocComment()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (array('final', 'internal') as $annotation) {
|
||||
if (false !== \strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$)#s', $doc, $notice)) {
|
||||
$message = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : '';
|
||||
self::${$annotation.'Methods'}[$class][$method->name] = array($class, $message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $deprecations;
|
||||
}
|
||||
|
||||
public function checkCase(\ReflectionClass $refl, $file, $class)
|
||||
{
|
||||
$real = explode('\\', $class.strrchr($file, '.'));
|
||||
$tail = explode(\DIRECTORY_SEPARATOR, str_replace('/', \DIRECTORY_SEPARATOR, $file));
|
||||
|
||||
$i = \count($tail) - 1;
|
||||
$j = \count($real) - 1;
|
||||
|
||||
while (isset($tail[$i], $real[$j]) && $tail[$i] === $real[$j]) {
|
||||
--$i;
|
||||
--$j;
|
||||
}
|
||||
|
||||
array_splice($tail, 0, $i + 1);
|
||||
|
||||
if (!$tail) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tail = \DIRECTORY_SEPARATOR.implode(\DIRECTORY_SEPARATOR, $tail);
|
||||
$tailLen = \strlen($tail);
|
||||
$real = $refl->getFileName();
|
||||
|
||||
if (2 === self::$caseCheck) {
|
||||
$real = $this->darwinRealpath($real);
|
||||
}
|
||||
|
||||
if (0 === substr_compare($real, $tail, -$tailLen, $tailLen, true)
|
||||
&& 0 !== substr_compare($real, $tail, -$tailLen, $tailLen, false)
|
||||
) {
|
||||
return array(substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `realpath` on MacOSX doesn't normalize the case of characters.
|
||||
*/
|
||||
private function darwinRealpath($real)
|
||||
{
|
||||
$i = 1 + strrpos($real, '/');
|
||||
$file = substr($real, $i);
|
||||
$real = substr($real, 0, $i);
|
||||
|
||||
if (isset(self::$darwinCache[$real])) {
|
||||
$kDir = $real;
|
||||
} else {
|
||||
$kDir = strtolower($real);
|
||||
|
||||
if (isset(self::$darwinCache[$kDir])) {
|
||||
$real = self::$darwinCache[$kDir][0];
|
||||
} else {
|
||||
$dir = getcwd();
|
||||
chdir($real);
|
||||
$real = getcwd().'/';
|
||||
chdir($dir);
|
||||
|
||||
$dir = $real;
|
||||
$k = $kDir;
|
||||
$i = \strlen($dir) - 1;
|
||||
while (!isset(self::$darwinCache[$k])) {
|
||||
self::$darwinCache[$k] = array($dir, array());
|
||||
self::$darwinCache[$dir] = &self::$darwinCache[$k];
|
||||
|
||||
while ('/' !== $dir[--$i]) {
|
||||
}
|
||||
$k = substr($k, 0, ++$i);
|
||||
$dir = substr($dir, 0, $i--);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dirFiles = self::$darwinCache[$kDir][1];
|
||||
|
||||
if (isset($dirFiles[$file])) {
|
||||
return $real .= $dirFiles[$file];
|
||||
}
|
||||
|
||||
$kFile = strtolower($file);
|
||||
|
||||
if (!isset($dirFiles[$kFile])) {
|
||||
foreach (scandir($real, 2) as $f) {
|
||||
if ('.' !== $f[0]) {
|
||||
$dirFiles[$f] = $f;
|
||||
if ($f === $file) {
|
||||
$kFile = $k = $file;
|
||||
} elseif ($f !== $k = strtolower($f)) {
|
||||
$dirFiles[$k] = $f;
|
||||
}
|
||||
}
|
||||
}
|
||||
self::$darwinCache[$kDir][1] = $dirFiles;
|
||||
}
|
||||
|
||||
return $real .= $dirFiles[$kFile];
|
||||
}
|
||||
|
||||
/**
|
||||
* `class_implements` includes interfaces from the parents so we have to manually exclude them.
|
||||
*
|
||||
* @param string $class
|
||||
* @param string|false $parent
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function getOwnInterfaces($class, $parent)
|
||||
{
|
||||
$ownInterfaces = class_implements($class, false);
|
||||
|
||||
if ($parent) {
|
||||
foreach (class_implements($parent, false) as $interface) {
|
||||
unset($ownInterfaces[$interface]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($ownInterfaces as $interface) {
|
||||
foreach (class_implements($interface) as $interface) {
|
||||
unset($ownInterfaces[$interface]);
|
||||
}
|
||||
}
|
||||
|
||||
return $ownInterfaces;
|
||||
}
|
||||
}
|
||||
|
||||
169
ErrorHandler.php
169
ErrorHandler.php
@@ -11,17 +11,17 @@
|
||||
|
||||
namespace Symfony\Component\Debug;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use Symfony\Component\Debug\Exception\ContextErrorException;
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use Symfony\Component\Debug\Exception\FatalThrowableError;
|
||||
use Symfony\Component\Debug\Exception\OutOfMemoryException;
|
||||
use Symfony\Component\Debug\Exception\SilencedErrorContext;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\FatalErrorHandlerInterface;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
|
||||
|
||||
/**
|
||||
* A generic ErrorHandler for the PHP engine.
|
||||
@@ -100,6 +100,8 @@ class ErrorHandler
|
||||
private static $stackedErrors = array();
|
||||
private static $stackedErrorLevels = array();
|
||||
private static $toStringException = null;
|
||||
private static $silencedErrorCache = array();
|
||||
private static $silencedErrorCount = 0;
|
||||
private static $exitCode = 0;
|
||||
|
||||
/**
|
||||
@@ -128,14 +130,28 @@ class ErrorHandler
|
||||
$handler->isRoot = true;
|
||||
}
|
||||
|
||||
if ($handlerIsNew && is_array($prev) && $prev[0] instanceof self) {
|
||||
if ($handlerIsNew && \is_array($prev) && $prev[0] instanceof self) {
|
||||
$handler = $prev[0];
|
||||
$replace = false;
|
||||
}
|
||||
if ($replace || !$prev) {
|
||||
$handler->setExceptionHandler(set_exception_handler(array($handler, 'handleException')));
|
||||
} else {
|
||||
if (!$replace && $prev) {
|
||||
restore_error_handler();
|
||||
$handlerIsRegistered = \is_array($prev) && $handler === $prev[0];
|
||||
} else {
|
||||
$handlerIsRegistered = true;
|
||||
}
|
||||
if (\is_array($prev = set_exception_handler(array($handler, 'handleException'))) && $prev[0] instanceof self) {
|
||||
restore_exception_handler();
|
||||
if (!$handlerIsRegistered) {
|
||||
$handler = $prev[0];
|
||||
} elseif ($handler !== $prev[0] && $replace) {
|
||||
set_exception_handler(array($handler, 'handleException'));
|
||||
$p = $prev[0]->setExceptionHandler(null);
|
||||
$handler->setExceptionHandler($p);
|
||||
$prev[0]->setExceptionHandler($p);
|
||||
}
|
||||
} else {
|
||||
$handler->setExceptionHandler($prev);
|
||||
}
|
||||
|
||||
$handler->throwAt(E_ALL & $handler->thrownErrors, true);
|
||||
@@ -164,7 +180,7 @@ class ErrorHandler
|
||||
{
|
||||
$loggers = array();
|
||||
|
||||
if (is_array($levels)) {
|
||||
if (\is_array($levels)) {
|
||||
foreach ($levels as $type => $logLevel) {
|
||||
if (empty($this->loggers[$type][0]) || $replace || $this->loggers[$type][0] === $this->bootstrappingLogger) {
|
||||
$loggers[$type] = array($logger, $logLevel);
|
||||
@@ -204,7 +220,7 @@ class ErrorHandler
|
||||
if (!isset($prev[$type])) {
|
||||
throw new \InvalidArgumentException('Unknown error type: '.$type);
|
||||
}
|
||||
if (!is_array($log)) {
|
||||
if (!\is_array($log)) {
|
||||
$log = array($log);
|
||||
} elseif (!array_key_exists(0, $log)) {
|
||||
throw new \InvalidArgumentException('No logger provided');
|
||||
@@ -337,7 +353,7 @@ class ErrorHandler
|
||||
{
|
||||
if ($prev !== $this->thrownErrors | $this->loggedErrors) {
|
||||
$handler = set_error_handler('var_dump');
|
||||
$handler = is_array($handler) ? $handler[0] : null;
|
||||
$handler = \is_array($handler) ? $handler[0] : null;
|
||||
restore_error_handler();
|
||||
if ($handler === $this) {
|
||||
restore_error_handler();
|
||||
@@ -367,18 +383,20 @@ class ErrorHandler
|
||||
public function handleError($type, $message, $file, $line)
|
||||
{
|
||||
// Level is the current error reporting level to manage silent error.
|
||||
$level = error_reporting();
|
||||
$silenced = 0 === ($level & $type);
|
||||
// Strong errors are not authorized to be silenced.
|
||||
$level = error_reporting() | E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
|
||||
$level |= E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
|
||||
$log = $this->loggedErrors & $type;
|
||||
$throw = $this->thrownErrors & $type & $level;
|
||||
$type &= $level | $this->screamedErrors;
|
||||
|
||||
if (!$type || (!$log && !$throw)) {
|
||||
return $type && $log;
|
||||
return !$silenced && $type && $log;
|
||||
}
|
||||
$scope = $this->scopedErrors & $type;
|
||||
|
||||
if (4 < $numArgs = func_num_args()) {
|
||||
if (4 < $numArgs = \func_num_args()) {
|
||||
$context = $scope ? (func_get_arg(4) ?: array()) : array();
|
||||
$backtrace = 5 < $numArgs ? func_get_arg(5) : null; // defined on HHVM
|
||||
} else {
|
||||
@@ -407,7 +425,28 @@ class ErrorHandler
|
||||
$errorAsException = self::$toStringException;
|
||||
self::$toStringException = null;
|
||||
} elseif (!$throw && !($type & $level)) {
|
||||
$errorAsException = new SilencedErrorContext($type, $file, $line);
|
||||
if (!isset(self::$silencedErrorCache[$id = $file.':'.$line])) {
|
||||
$lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3), $type, $file, $line, false) : array();
|
||||
$errorAsException = new SilencedErrorContext($type, $file, $line, $lightTrace);
|
||||
} elseif (isset(self::$silencedErrorCache[$id][$message])) {
|
||||
$lightTrace = null;
|
||||
$errorAsException = self::$silencedErrorCache[$id][$message];
|
||||
++$errorAsException->count;
|
||||
} else {
|
||||
$lightTrace = array();
|
||||
$errorAsException = null;
|
||||
}
|
||||
|
||||
if (100 < ++self::$silencedErrorCount) {
|
||||
self::$silencedErrorCache = $lightTrace = array();
|
||||
self::$silencedErrorCount = 1;
|
||||
}
|
||||
if ($errorAsException) {
|
||||
self::$silencedErrorCache[$id][$message] = $errorAsException;
|
||||
}
|
||||
if (null === $lightTrace) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ($scope) {
|
||||
$errorAsException = new ContextErrorException($logMessage, 0, $type, $file, $line, $context);
|
||||
@@ -418,19 +457,7 @@ class ErrorHandler
|
||||
// Clean the trace by removing function arguments and the first frames added by the error handler itself.
|
||||
if ($throw || $this->tracedErrors & $type) {
|
||||
$backtrace = $backtrace ?: $errorAsException->getTrace();
|
||||
$lightTrace = $backtrace;
|
||||
|
||||
for ($i = 0; isset($backtrace[$i]); ++$i) {
|
||||
if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
|
||||
$lightTrace = array_slice($lightTrace, 1 + $i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!($throw || $this->scopedErrors & $type)) {
|
||||
for ($i = 0; isset($lightTrace[$i]); ++$i) {
|
||||
unset($lightTrace[$i]['args']);
|
||||
}
|
||||
}
|
||||
$lightTrace = $this->cleanTrace($backtrace, $type, $file, $line, $throw);
|
||||
$this->traceReflector->setValue($errorAsException, $lightTrace);
|
||||
} else {
|
||||
$this->traceReflector->setValue($errorAsException, array());
|
||||
@@ -487,19 +514,19 @@ class ErrorHandler
|
||||
$this->loggers[$type][0],
|
||||
($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG,
|
||||
$logMessage,
|
||||
array('exception' => $errorAsException),
|
||||
$errorAsException ? array('exception' => $errorAsException) : array(),
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
$this->isRecursive = true;
|
||||
$level = ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG;
|
||||
$this->loggers[$type][0]->log($level, $logMessage, array('exception' => $errorAsException));
|
||||
$this->loggers[$type][0]->log($level, $logMessage, $errorAsException ? array('exception' => $errorAsException) : array());
|
||||
} finally {
|
||||
$this->isRecursive = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $type && $log;
|
||||
return !$silenced && $type && $log;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -519,6 +546,7 @@ class ErrorHandler
|
||||
$exception = new FatalThrowableError($exception);
|
||||
}
|
||||
$type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
|
||||
$handlerException = null;
|
||||
|
||||
if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
|
||||
if ($exception instanceof FatalErrorException) {
|
||||
@@ -534,9 +562,6 @@ class ErrorHandler
|
||||
}
|
||||
} elseif ($exception instanceof \ErrorException) {
|
||||
$message = 'Uncaught '.$exception->getMessage();
|
||||
if ($exception instanceof ContextErrorException) {
|
||||
$e['context'] = $exception->getContext();
|
||||
}
|
||||
} else {
|
||||
$message = 'Uncaught Exception: '.$exception->getMessage();
|
||||
}
|
||||
@@ -556,18 +581,21 @@ class ErrorHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($this->exceptionHandler)) {
|
||||
throw $exception; // Give back $exception to the native handler
|
||||
}
|
||||
$exceptionHandler = $this->exceptionHandler;
|
||||
$this->exceptionHandler = null;
|
||||
try {
|
||||
call_user_func($this->exceptionHandler, $exception);
|
||||
if (null !== $exceptionHandler) {
|
||||
return \call_user_func($exceptionHandler, $exception);
|
||||
}
|
||||
$handlerException = $handlerException ?: $exception;
|
||||
} catch (\Exception $handlerException) {
|
||||
} catch (\Throwable $handlerException) {
|
||||
}
|
||||
if (isset($handlerException)) {
|
||||
$this->exceptionHandler = null;
|
||||
$this->handleException($handlerException);
|
||||
if ($exception === $handlerException) {
|
||||
self::$reservedMemory = null; // Disable the fatal error handler
|
||||
throw $exception; // Give back $exception to the native handler
|
||||
}
|
||||
$this->handleException($handlerException);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -583,15 +611,39 @@ class ErrorHandler
|
||||
return;
|
||||
}
|
||||
|
||||
self::$reservedMemory = null;
|
||||
$handler = self::$reservedMemory = null;
|
||||
$handlers = array();
|
||||
$previousHandler = null;
|
||||
$sameHandlerLimit = 10;
|
||||
|
||||
$handler = set_error_handler('var_dump');
|
||||
$handler = is_array($handler) ? $handler[0] : null;
|
||||
restore_error_handler();
|
||||
while (!\is_array($handler) || !$handler[0] instanceof self) {
|
||||
$handler = set_exception_handler('var_dump');
|
||||
restore_exception_handler();
|
||||
|
||||
if (!$handler instanceof self) {
|
||||
if (!$handler) {
|
||||
break;
|
||||
}
|
||||
restore_exception_handler();
|
||||
|
||||
if ($handler !== $previousHandler) {
|
||||
array_unshift($handlers, $handler);
|
||||
$previousHandler = $handler;
|
||||
} elseif (0 === --$sameHandlerLimit) {
|
||||
$handler = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach ($handlers as $h) {
|
||||
set_exception_handler($h);
|
||||
}
|
||||
if (!$handler) {
|
||||
return;
|
||||
}
|
||||
if ($handler !== $h) {
|
||||
$handler[0]->setExceptionHandler($h);
|
||||
}
|
||||
$handler = $handler[0];
|
||||
$handlers = array();
|
||||
|
||||
if ($exit = null === $error) {
|
||||
$error = error_get_last();
|
||||
@@ -644,17 +696,25 @@ class ErrorHandler
|
||||
*
|
||||
* The most important feature of this is to prevent
|
||||
* autoloading until unstackErrors() is called.
|
||||
*
|
||||
* @deprecated since version 3.4, to be removed in 4.0.
|
||||
*/
|
||||
public static function stackErrors()
|
||||
{
|
||||
@trigger_error('Support for stacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
|
||||
|
||||
self::$stackedErrorLevels[] = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unstacks stacked errors and forwards to the logger.
|
||||
*
|
||||
* @deprecated since version 3.4, to be removed in 4.0.
|
||||
*/
|
||||
public static function unstackErrors()
|
||||
{
|
||||
@trigger_error('Support for unstacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
|
||||
|
||||
$level = array_pop(self::$stackedErrorLevels);
|
||||
|
||||
if (null !== $level) {
|
||||
@@ -690,4 +750,23 @@ class ErrorHandler
|
||||
new ClassNotFoundFatalErrorHandler(),
|
||||
);
|
||||
}
|
||||
|
||||
private function cleanTrace($backtrace, $type, $file, $line, $throw)
|
||||
{
|
||||
$lightTrace = $backtrace;
|
||||
|
||||
for ($i = 0; isset($backtrace[$i]); ++$i) {
|
||||
if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
|
||||
$lightTrace = \array_slice($lightTrace, 1 + $i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!($throw || $this->scopedErrors & $type)) {
|
||||
for ($i = 0; isset($lightTrace[$i]); ++$i) {
|
||||
unset($lightTrace[$i]['args'], $lightTrace[$i]['object']);
|
||||
}
|
||||
}
|
||||
|
||||
return $lightTrace;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ class ClassNotFoundException extends FatalErrorException
|
||||
$previous->getSeverity(),
|
||||
$previous->getFile(),
|
||||
$previous->getLine(),
|
||||
null,
|
||||
true,
|
||||
null,
|
||||
$previous->getPrevious()
|
||||
);
|
||||
$this->setTrace($previous->getTrace());
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Symfony\Component\Debug\Exception;
|
||||
* Error Exception with Variable Context.
|
||||
*
|
||||
* @author Christian Sciberras <uuf6429@gmail.com>
|
||||
*
|
||||
* @deprecated since version 3.3. Instead, \ErrorException will be used directly in 4.0.
|
||||
*/
|
||||
class ContextErrorException extends \ErrorException
|
||||
{
|
||||
@@ -31,6 +33,8 @@ class ContextErrorException extends \ErrorException
|
||||
*/
|
||||
public function getContext()
|
||||
{
|
||||
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED);
|
||||
|
||||
return $this->context;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ namespace Symfony\Component\Debug\Exception;
|
||||
*/
|
||||
class FatalErrorException extends \ErrorException
|
||||
{
|
||||
public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true, array $trace = null)
|
||||
public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true, array $trace = null, $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $severity, $filename, $lineno);
|
||||
parent::__construct($message, $code, $severity, $filename, $lineno, $previous);
|
||||
|
||||
if (null !== $trace) {
|
||||
if (!$traceArgs) {
|
||||
@@ -31,7 +31,7 @@ class FatalErrorException extends \ErrorException
|
||||
|
||||
$this->setTrace($trace);
|
||||
} elseif (null !== $traceOffset) {
|
||||
if (function_exists('xdebug_get_function_stack')) {
|
||||
if (\function_exists('xdebug_get_function_stack')) {
|
||||
$trace = xdebug_get_function_stack();
|
||||
if (0 < $traceOffset) {
|
||||
array_splice($trace, -$traceOffset);
|
||||
@@ -60,7 +60,7 @@ class FatalErrorException extends \ErrorException
|
||||
|
||||
unset($frame);
|
||||
$trace = array_reverse($trace);
|
||||
} elseif (function_exists('symfony_debug_backtrace')) {
|
||||
} elseif (\function_exists('symfony_debug_backtrace')) {
|
||||
$trace = symfony_debug_backtrace();
|
||||
if (0 < $traceOffset) {
|
||||
array_splice($trace, 0, $traceOffset);
|
||||
|
||||
@@ -36,7 +36,8 @@ class FatalThrowableError extends FatalErrorException
|
||||
$e->getCode(),
|
||||
$severity,
|
||||
$e->getFile(),
|
||||
$e->getLine()
|
||||
$e->getLine(),
|
||||
$e->getPrevious()
|
||||
);
|
||||
|
||||
$this->setTrace($e->getTrace());
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Component\Debug\Exception;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
|
||||
/**
|
||||
@@ -41,6 +42,8 @@ class FlattenException
|
||||
if ($exception instanceof HttpExceptionInterface) {
|
||||
$statusCode = $exception->getStatusCode();
|
||||
$headers = array_merge($headers, $exception->getHeaders());
|
||||
} elseif ($exception instanceof RequestExceptionInterface) {
|
||||
$statusCode = 400;
|
||||
}
|
||||
|
||||
if (null === $statusCode) {
|
||||
@@ -50,7 +53,7 @@ class FlattenException
|
||||
$e->setStatusCode($statusCode);
|
||||
$e->setHeaders($headers);
|
||||
$e->setTraceFromException($exception);
|
||||
$e->setClass(get_class($exception));
|
||||
$e->setClass(\get_class($exception));
|
||||
$e->setFile($exception->getFile());
|
||||
$e->setLine($exception->getLine());
|
||||
|
||||
@@ -154,7 +157,7 @@ class FlattenException
|
||||
return $this->previous;
|
||||
}
|
||||
|
||||
public function setPrevious(FlattenException $previous)
|
||||
public function setPrevious(self $previous)
|
||||
{
|
||||
$this->previous = $previous;
|
||||
}
|
||||
@@ -225,9 +228,9 @@ class FlattenException
|
||||
if ($value instanceof \__PHP_Incomplete_Class) {
|
||||
// is_object() returns false on PHP<=7.1
|
||||
$result[$key] = array('incomplete-object', $this->getClassNameFromIncomplete($value));
|
||||
} elseif (is_object($value)) {
|
||||
$result[$key] = array('object', get_class($value));
|
||||
} elseif (is_array($value)) {
|
||||
} elseif (\is_object($value)) {
|
||||
$result[$key] = array('object', \get_class($value));
|
||||
} elseif (\is_array($value)) {
|
||||
if ($level > 10) {
|
||||
$result[$key] = array('array', '*DEEP NESTED ARRAY*');
|
||||
} else {
|
||||
@@ -235,13 +238,13 @@ class FlattenException
|
||||
}
|
||||
} elseif (null === $value) {
|
||||
$result[$key] = array('null', null);
|
||||
} elseif (is_bool($value)) {
|
||||
} elseif (\is_bool($value)) {
|
||||
$result[$key] = array('boolean', $value);
|
||||
} elseif (is_int($value)) {
|
||||
} elseif (\is_int($value)) {
|
||||
$result[$key] = array('integer', $value);
|
||||
} elseif (is_float($value)) {
|
||||
} elseif (\is_float($value)) {
|
||||
$result[$key] = array('float', $value);
|
||||
} elseif (is_resource($value)) {
|
||||
} elseif (\is_resource($value)) {
|
||||
$result[$key] = array('resource', get_resource_type($value));
|
||||
} else {
|
||||
$result[$key] = array('string', (string) $value);
|
||||
|
||||
@@ -18,15 +18,20 @@ namespace Symfony\Component\Debug\Exception;
|
||||
*/
|
||||
class SilencedErrorContext implements \JsonSerializable
|
||||
{
|
||||
public $count = 1;
|
||||
|
||||
private $severity;
|
||||
private $file;
|
||||
private $line;
|
||||
private $trace;
|
||||
|
||||
public function __construct($severity, $file, $line)
|
||||
public function __construct($severity, $file, $line, array $trace = array(), $count = 1)
|
||||
{
|
||||
$this->severity = $severity;
|
||||
$this->file = $file;
|
||||
$this->line = $line;
|
||||
$this->trace = $trace;
|
||||
$this->count = $count;
|
||||
}
|
||||
|
||||
public function getSeverity()
|
||||
@@ -44,12 +49,19 @@ class SilencedErrorContext implements \JsonSerializable
|
||||
return $this->line;
|
||||
}
|
||||
|
||||
public function getTrace()
|
||||
{
|
||||
return $this->trace;
|
||||
}
|
||||
|
||||
public function JsonSerialize()
|
||||
{
|
||||
return array(
|
||||
'severity' => $this->severity,
|
||||
'file' => $this->file,
|
||||
'line' => $this->line,
|
||||
'trace' => $this->trace,
|
||||
'count' => $this->count,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ class UndefinedFunctionException extends FatalErrorException
|
||||
$previous->getSeverity(),
|
||||
$previous->getFile(),
|
||||
$previous->getLine(),
|
||||
null,
|
||||
true,
|
||||
null,
|
||||
$previous->getPrevious()
|
||||
);
|
||||
$this->setTrace($previous->getTrace());
|
||||
|
||||
@@ -26,6 +26,9 @@ class UndefinedMethodException extends FatalErrorException
|
||||
$previous->getSeverity(),
|
||||
$previous->getFile(),
|
||||
$previous->getLine(),
|
||||
null,
|
||||
true,
|
||||
null,
|
||||
$previous->getPrevious()
|
||||
);
|
||||
$this->setTrace($previous->getTrace());
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -11,11 +11,11 @@
|
||||
|
||||
namespace Symfony\Component\Debug\FatalErrorHandler;
|
||||
|
||||
use Symfony\Component\Debug\Exception\ClassNotFoundException;
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use Symfony\Component\Debug\DebugClassLoader;
|
||||
use Composer\Autoload\ClassLoader as ComposerClassLoader;
|
||||
use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader;
|
||||
use Symfony\Component\Debug\DebugClassLoader;
|
||||
use Symfony\Component\Debug\Exception\ClassNotFoundException;
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
|
||||
/**
|
||||
* ErrorHandler for classes that do not exist.
|
||||
@@ -29,9 +29,9 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
*/
|
||||
public function handleError(array $error, FatalErrorException $exception)
|
||||
{
|
||||
$messageLen = strlen($error['message']);
|
||||
$messageLen = \strlen($error['message']);
|
||||
$notFoundSuffix = '\' not found';
|
||||
$notFoundSuffixLen = strlen($notFoundSuffix);
|
||||
$notFoundSuffixLen = \strlen($notFoundSuffix);
|
||||
if ($notFoundSuffixLen > $messageLen) {
|
||||
return;
|
||||
}
|
||||
@@ -42,7 +42,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
|
||||
foreach (array('class', 'interface', 'trait') as $typeName) {
|
||||
$prefix = ucfirst($typeName).' \'';
|
||||
$prefixLen = strlen($prefix);
|
||||
$prefixLen = \strlen($prefix);
|
||||
if (0 !== strpos($error['message'], $prefix)) {
|
||||
continue;
|
||||
}
|
||||
@@ -85,7 +85,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
*/
|
||||
private function getClassCandidates($class)
|
||||
{
|
||||
if (!is_array($functions = spl_autoload_functions())) {
|
||||
if (!\is_array($functions = spl_autoload_functions())) {
|
||||
return array();
|
||||
}
|
||||
|
||||
@@ -93,14 +93,14 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
$classes = array();
|
||||
|
||||
foreach ($functions as $function) {
|
||||
if (!is_array($function)) {
|
||||
if (!\is_array($function)) {
|
||||
continue;
|
||||
}
|
||||
// get class loaders wrapped by DebugClassLoader
|
||||
if ($function[0] instanceof DebugClassLoader) {
|
||||
$function = $function[0]->getClassLoader();
|
||||
|
||||
if (!is_array($function)) {
|
||||
if (!\is_array($function)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
*/
|
||||
private function findClassInPath($path, $class, $prefix)
|
||||
{
|
||||
if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
|
||||
if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
{
|
||||
$candidates = array(
|
||||
// namespaced class
|
||||
$namespacedClass = str_replace(array($path.DIRECTORY_SEPARATOR, '.php', '/'), array('', '', '\\'), $file),
|
||||
$namespacedClass = str_replace(array($path.\DIRECTORY_SEPARATOR, '.php', '/'), array('', '', '\\'), $file),
|
||||
// namespaced class (with target dir)
|
||||
$prefix.$namespacedClass,
|
||||
// namespaced class (with target dir and separator)
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
namespace Symfony\Component\Debug\FatalErrorHandler;
|
||||
|
||||
use Symfony\Component\Debug\Exception\UndefinedFunctionException;
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use Symfony\Component\Debug\Exception\UndefinedFunctionException;
|
||||
|
||||
/**
|
||||
* ErrorHandler for undefined functions.
|
||||
@@ -26,9 +26,9 @@ class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
*/
|
||||
public function handleError(array $error, FatalErrorException $exception)
|
||||
{
|
||||
$messageLen = strlen($error['message']);
|
||||
$messageLen = \strlen($error['message']);
|
||||
$notFoundSuffix = '()';
|
||||
$notFoundSuffixLen = strlen($notFoundSuffix);
|
||||
$notFoundSuffixLen = \strlen($notFoundSuffix);
|
||||
if ($notFoundSuffixLen > $messageLen) {
|
||||
return;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
}
|
||||
|
||||
$prefix = 'Call to undefined function ';
|
||||
$prefixLen = strlen($prefix);
|
||||
$prefixLen = \strlen($prefix);
|
||||
if (0 !== strpos($error['message'], $prefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
$candidates = array();
|
||||
foreach ($methods as $definedMethodName) {
|
||||
$lev = levenshtein($methodName, $definedMethodName);
|
||||
if ($lev <= strlen($methodName) / 3 || false !== strpos($definedMethodName, $methodName)) {
|
||||
if ($lev <= \strlen($methodName) / 3 || false !== strpos($definedMethodName, $methodName)) {
|
||||
$candidates[] = $definedMethodName;
|
||||
}
|
||||
}
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2004-2017 Fabien Potencier
|
||||
Copyright (c) 2004-2018 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
--TEST--
|
||||
Test symfony_zval_info API
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
|
||||
<?php if (!extension_loaded('symfony_debug')) {
|
||||
echo 'skip';
|
||||
} ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
--TEST--
|
||||
Test symfony_debug_backtrace in case of fatal error
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
|
||||
<?php if (!extension_loaded('symfony_debug')) {
|
||||
echo 'skip';
|
||||
} ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
--TEST--
|
||||
Test symfony_debug_backtrace in case of non fatal error
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
|
||||
<?php if (!extension_loaded('symfony_debug')) {
|
||||
echo 'skip';
|
||||
} ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
--TEST--
|
||||
Test ErrorHandler in case of fatal error
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded('symfony_debug')) print 'skip'; ?>
|
||||
<?php if (!extension_loaded('symfony_debug')) {
|
||||
echo 'skip';
|
||||
} ?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
@@ -43,7 +45,7 @@ function foo()
|
||||
$handler = ErrorHandler::register();
|
||||
$handler->setExceptionHandler('print_r');
|
||||
|
||||
if (function_exists('xdebug_disable')) {
|
||||
if (\function_exists('xdebug_disable')) {
|
||||
xdebug_disable();
|
||||
}
|
||||
|
||||
|
||||
@@ -59,9 +59,26 @@ class DebugClassLoaderTest extends TestCase
|
||||
$this->fail('DebugClassLoader did not register');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessage boo
|
||||
*/
|
||||
public function testThrowingClass()
|
||||
{
|
||||
try {
|
||||
class_exists(__NAMESPACE__.'\Fixtures\Throwing');
|
||||
$this->fail('Exception expected');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertSame('boo', $e->getMessage());
|
||||
}
|
||||
|
||||
// the second call also should throw
|
||||
class_exists(__NAMESPACE__.'\Fixtures\Throwing');
|
||||
}
|
||||
|
||||
public function testUnsilencing()
|
||||
{
|
||||
if (PHP_VERSION_ID >= 70000) {
|
||||
if (\PHP_VERSION_ID >= 70000) {
|
||||
$this->markTestSkipped('PHP7 throws exceptions, unsilencing is not required anymore.');
|
||||
}
|
||||
if (defined('HHVM_VERSION')) {
|
||||
@@ -109,7 +126,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
} catch (\ErrorException $exception) {
|
||||
// if an exception is thrown, the test passed
|
||||
$this->assertStringStartsWith(__FILE__, $exception->getFile());
|
||||
if (PHP_VERSION_ID < 70000) {
|
||||
if (\PHP_VERSION_ID < 70000) {
|
||||
$this->assertRegExp('/^Runtime Notice: Declaration/', $exception->getMessage());
|
||||
$this->assertEquals(E_STRICT, $exception->getSeverity());
|
||||
} else {
|
||||
@@ -124,6 +141,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedExceptionMessage Case mismatch between loaded and declared class names
|
||||
*/
|
||||
public function testNameCaseMismatch()
|
||||
{
|
||||
@@ -145,6 +163,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedExceptionMessage Case mismatch between loaded and declared class names
|
||||
*/
|
||||
public function testPsr4CaseMismatch()
|
||||
{
|
||||
@@ -185,7 +204,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
|
||||
$xError = array(
|
||||
'type' => E_USER_DEPRECATED,
|
||||
'message' => 'The Test\Symfony\Component\Debug\Tests\\'.$class.' class '.$type.' Symfony\Component\Debug\Tests\Fixtures\\'.$super.' that is deprecated but this is a test deprecation notice.',
|
||||
'message' => 'The "Test\Symfony\Component\Debug\Tests\\'.$class.'" class '.$type.' "Symfony\Component\Debug\Tests\Fixtures\\'.$super.'" that is deprecated but this is a test deprecation notice.',
|
||||
);
|
||||
|
||||
$this->assertSame($xError, $lastError);
|
||||
@@ -245,7 +264,7 @@ class DebugClassLoaderTest extends TestCase
|
||||
|
||||
public function testReservedForPhp7()
|
||||
{
|
||||
if (PHP_VERSION_ID >= 70000) {
|
||||
if (\PHP_VERSION_ID >= 70000) {
|
||||
$this->markTestSkipped('PHP7 already prevents using reserved names.');
|
||||
}
|
||||
|
||||
@@ -263,11 +282,102 @@ class DebugClassLoaderTest extends TestCase
|
||||
|
||||
$xError = array(
|
||||
'type' => E_USER_DEPRECATED,
|
||||
'message' => 'Test\Symfony\Component\Debug\Tests\Float uses a reserved class name (Float) that will break on PHP 7 and higher',
|
||||
'message' => 'The "Test\Symfony\Component\Debug\Tests\Float" class uses the reserved name "Float", it will break on PHP 7 and higher',
|
||||
);
|
||||
|
||||
$this->assertSame($xError, $lastError);
|
||||
}
|
||||
|
||||
public function testExtendedFinalClass()
|
||||
{
|
||||
set_error_handler(function () { return false; });
|
||||
$e = error_reporting(0);
|
||||
trigger_error('', E_USER_NOTICE);
|
||||
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\ExtendsFinalClass', true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
|
||||
$lastError = error_get_last();
|
||||
unset($lastError['file'], $lastError['line']);
|
||||
|
||||
$xError = array(
|
||||
'type' => E_USER_DEPRECATED,
|
||||
'message' => 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass" class is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass".',
|
||||
);
|
||||
|
||||
$this->assertSame($xError, $lastError);
|
||||
}
|
||||
|
||||
public function testExtendedFinalMethod()
|
||||
{
|
||||
$deprecations = array();
|
||||
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
|
||||
$e = error_reporting(E_USER_DEPRECATED);
|
||||
|
||||
class_exists(__NAMESPACE__.'\\Fixtures\\ExtendedFinalMethod', true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
|
||||
$xError = array(
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" method is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod2()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".',
|
||||
);
|
||||
|
||||
$this->assertSame($xError, $deprecations);
|
||||
}
|
||||
|
||||
public function testExtendedDeprecatedMethodDoesntTriggerAnyNotice()
|
||||
{
|
||||
set_error_handler(function () { return false; });
|
||||
$e = error_reporting(0);
|
||||
trigger_error('', E_USER_NOTICE);
|
||||
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\ExtendsAnnotatedClass', true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
|
||||
$lastError = error_get_last();
|
||||
unset($lastError['file'], $lastError['line']);
|
||||
|
||||
$this->assertSame(array('type' => E_USER_NOTICE, 'message' => ''), $lastError);
|
||||
}
|
||||
|
||||
public function testInternalsUse()
|
||||
{
|
||||
$deprecations = array();
|
||||
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
|
||||
$e = error_reporting(E_USER_DEPRECATED);
|
||||
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\ExtendsInternals', true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
|
||||
$this->assertSame($deprecations, array(
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\InternalInterface" interface is considered internal. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternalsParent".',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass" class is considered internal since version 3.4. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternalsParent".',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\InternalTrait" trait is considered internal. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".',
|
||||
'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass::internalMethod()" method is considered internal since version 3.4. It may change without further notice. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".',
|
||||
));
|
||||
}
|
||||
|
||||
public function testUseTraitWithInternalMethod()
|
||||
{
|
||||
$deprecations = array();
|
||||
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
|
||||
$e = error_reporting(E_USER_DEPRECATED);
|
||||
|
||||
class_exists('Test\\'.__NAMESPACE__.'\\UseTraitWithInternalMethod', true);
|
||||
|
||||
error_reporting($e);
|
||||
restore_error_handler();
|
||||
|
||||
$this->assertSame(array(), $deprecations);
|
||||
}
|
||||
}
|
||||
|
||||
class ClassLoader
|
||||
@@ -291,16 +401,12 @@ class ClassLoader
|
||||
eval('namespace '.__NAMESPACE__.'; class TestingStacking { function foo() {} }');
|
||||
} elseif (__NAMESPACE__.'\TestingCaseMismatch' === $class) {
|
||||
eval('namespace '.__NAMESPACE__.'; class TestingCaseMisMatch {}');
|
||||
} elseif (__NAMESPACE__.'\Fixtures\CaseMismatch' === $class) {
|
||||
return $fixtureDir.'CaseMismatch.php';
|
||||
} elseif (__NAMESPACE__.'\Fixtures\Psr4CaseMismatch' === $class) {
|
||||
return $fixtureDir.'psr4'.DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php';
|
||||
} elseif (__NAMESPACE__.'\Fixtures\NotPSR0' === $class) {
|
||||
return $fixtureDir.'reallyNotPsr0.php';
|
||||
} elseif (__NAMESPACE__.'\Fixtures\NotPSR0bis' === $class) {
|
||||
return $fixtureDir.'notPsr0Bis.php';
|
||||
} elseif (__NAMESPACE__.'\Fixtures\DeprecatedInterface' === $class) {
|
||||
return $fixtureDir.'DeprecatedInterface.php';
|
||||
} elseif ('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent' === $class) {
|
||||
eval('namespace Symfony\Bridge\Debug\Tests\Fixtures; class ExtendsDeprecatedParent extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\DeprecatedParentClass' === $class) {
|
||||
@@ -311,6 +417,22 @@ class ClassLoader
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class NonDeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\NonDeprecatedInterface {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\Float' === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class Float {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsFinalClass' === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsFinalClass extends \\'.__NAMESPACE__.'\Fixtures\FinalClass {}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsAnnotatedClass' === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsAnnotatedClass extends \\'.__NAMESPACE__.'\Fixtures\AnnotatedClass {
|
||||
public function deprecatedMethod() { }
|
||||
}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsInternals' === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternals extends ExtendsInternalsParent {
|
||||
use \\'.__NAMESPACE__.'\Fixtures\InternalTrait;
|
||||
|
||||
public function internalMethod() { }
|
||||
}');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsInternalsParent' === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternalsParent extends \\'.__NAMESPACE__.'\Fixtures\InternalClass implements \\'.__NAMESPACE__.'\Fixtures\InternalInterface { }');
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\UseTraitWithInternalMethod' === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class UseTraitWithInternalMethod { use \\'.__NAMESPACE__.'\Fixtures\TraitWithInternalMethod; }');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LogLevel;
|
||||
use Symfony\Component\Debug\BufferingLogger;
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\Exception\ContextErrorException;
|
||||
use Symfony\Component\Debug\Exception\SilencedErrorContext;
|
||||
|
||||
/**
|
||||
@@ -36,7 +35,7 @@ class ErrorHandlerTest extends TestCase
|
||||
|
||||
$newHandler = new ErrorHandler();
|
||||
|
||||
$this->assertSame($newHandler, ErrorHandler::register($newHandler, false));
|
||||
$this->assertSame($handler, ErrorHandler::register($newHandler, false));
|
||||
$h = set_error_handler('var_dump');
|
||||
restore_error_handler();
|
||||
$this->assertSame(array($handler, 'handleError'), $h);
|
||||
@@ -66,19 +65,42 @@ class ErrorHandlerTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testErrorGetLast()
|
||||
{
|
||||
$handler = ErrorHandler::register();
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$handler->setDefaultLogger($logger);
|
||||
$handler->screamAt(E_ALL);
|
||||
|
||||
try {
|
||||
@trigger_error('Hello', E_USER_WARNING);
|
||||
$expected = array(
|
||||
'type' => E_USER_WARNING,
|
||||
'message' => 'Hello',
|
||||
'file' => __FILE__,
|
||||
'line' => __LINE__ - 5,
|
||||
);
|
||||
$this->assertSame($expected, error_get_last());
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function testNotice()
|
||||
{
|
||||
ErrorHandler::register();
|
||||
|
||||
try {
|
||||
self::triggerNotice($this);
|
||||
$this->fail('ContextErrorException expected');
|
||||
} catch (ContextErrorException $exception) {
|
||||
$this->fail('ErrorException expected');
|
||||
} catch (\ErrorException $exception) {
|
||||
// if an exception is thrown, the test passed
|
||||
$this->assertEquals(E_NOTICE, $exception->getSeverity());
|
||||
$this->assertEquals(__FILE__, $exception->getFile());
|
||||
$this->assertRegExp('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
|
||||
$this->assertArrayHasKey('foobar', $exception->getContext());
|
||||
|
||||
$trace = $exception->getTrace();
|
||||
|
||||
@@ -100,8 +122,6 @@ class ErrorHandlerTest extends TestCase
|
||||
// dummy function to test trace in error handler.
|
||||
private static function triggerNotice($that)
|
||||
{
|
||||
// dummy variable to check for in error handler.
|
||||
$foobar = 123;
|
||||
$that->assertSame('', $foo.$foo.$bar);
|
||||
}
|
||||
|
||||
@@ -223,12 +243,17 @@ class ErrorHandlerTest extends TestCase
|
||||
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
$line = null;
|
||||
$logArgCheck = function ($level, $message, $context) use (&$line) {
|
||||
$this->assertEquals('Notice: Undefined variable: undefVar', $message);
|
||||
$this->assertArrayHasKey('exception', $context);
|
||||
$exception = $context['exception'];
|
||||
$this->assertInstanceOf(SilencedErrorContext::class, $exception);
|
||||
$this->assertSame(E_NOTICE, $exception->getSeverity());
|
||||
$this->assertSame(__FILE__, $exception->getFile());
|
||||
$this->assertSame($line, $exception->getLine());
|
||||
$this->assertNotEmpty($exception->getTrace());
|
||||
$this->assertSame(1, $exception->count);
|
||||
};
|
||||
|
||||
$logger
|
||||
@@ -241,6 +266,7 @@ class ErrorHandlerTest extends TestCase
|
||||
$handler->setDefaultLogger($logger, E_NOTICE);
|
||||
$handler->screamAt(E_NOTICE);
|
||||
unset($undefVar);
|
||||
$line = __LINE__ + 1;
|
||||
@$undefVar++;
|
||||
|
||||
restore_error_handler();
|
||||
@@ -297,6 +323,9 @@ class ErrorHandlerTest extends TestCase
|
||||
@$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, array());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group no-hhvm
|
||||
*/
|
||||
public function testHandleException()
|
||||
{
|
||||
try {
|
||||
@@ -338,6 +367,9 @@ class ErrorHandlerTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testErrorStacking()
|
||||
{
|
||||
try {
|
||||
@@ -418,6 +450,9 @@ class ErrorHandlerTest extends TestCase
|
||||
$handler->setLoggers(array(E_DEPRECATED => array($mockLogger, LogLevel::WARNING)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group no-hhvm
|
||||
*/
|
||||
public function testSettingLoggerWhenExceptionIsBuffered()
|
||||
{
|
||||
$bootLogger = new BufferingLogger();
|
||||
@@ -437,6 +472,9 @@ class ErrorHandlerTest extends TestCase
|
||||
$handler->handleException($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group no-hhvm
|
||||
*/
|
||||
public function testHandleFatalError()
|
||||
{
|
||||
try {
|
||||
@@ -486,7 +524,7 @@ class ErrorHandlerTest extends TestCase
|
||||
|
||||
$handler = new ErrorHandler();
|
||||
$handler->setExceptionHandler(function () use (&$args) {
|
||||
$args = func_get_args();
|
||||
$args = \func_get_args();
|
||||
});
|
||||
|
||||
$handler->handleException($exception);
|
||||
@@ -495,6 +533,9 @@ class ErrorHandlerTest extends TestCase
|
||||
$this->assertStringStartsWith("Attempted to load class \"Foo\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group no-hhvm
|
||||
*/
|
||||
public function testHandleFatalErrorOnHHVM()
|
||||
{
|
||||
try {
|
||||
@@ -521,11 +562,25 @@ class ErrorHandlerTest extends TestCase
|
||||
'backtrace' => array(456),
|
||||
);
|
||||
|
||||
call_user_func_array(array($handler, 'handleError'), $error);
|
||||
\call_user_func_array(array($handler, 'handleError'), $error);
|
||||
$handler->handleFatalError($error);
|
||||
} finally {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
* @group no-hhvm
|
||||
*/
|
||||
public function testCustomExceptionHandler()
|
||||
{
|
||||
$handler = new ErrorHandler();
|
||||
$handler->setExceptionHandler(function ($e) use ($handler) {
|
||||
$handler->handleException($e);
|
||||
});
|
||||
|
||||
$handler->handleException(new \Exception());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,19 +13,20 @@ namespace Symfony\Component\Debug\Tests\Exception;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Debug\Exception\FlattenException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
|
||||
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\GoneHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\LengthRequiredHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\PreconditionRequiredHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
|
||||
|
||||
class FlattenExceptionTest extends TestCase
|
||||
@@ -79,6 +80,11 @@ class FlattenExceptionTest extends TestCase
|
||||
|
||||
$flattened = FlattenException::create(new UnsupportedMediaTypeHttpException());
|
||||
$this->assertEquals('415', $flattened->getStatusCode());
|
||||
|
||||
if (class_exists(SuspiciousOperationException::class)) {
|
||||
$flattened = FlattenException::create(new SuspiciousOperationException());
|
||||
$this->assertEquals('400', $flattened->getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
public function testHeadersForHttpException()
|
||||
@@ -105,7 +111,7 @@ class FlattenExceptionTest extends TestCase
|
||||
/**
|
||||
* @dataProvider flattenDataProvider
|
||||
*/
|
||||
public function testFlattenHttpException(\Exception $exception, $statusCode)
|
||||
public function testFlattenHttpException(\Exception $exception)
|
||||
{
|
||||
$flattened = FlattenException::create($exception);
|
||||
$flattened2 = FlattenException::create($exception);
|
||||
@@ -120,7 +126,7 @@ class FlattenExceptionTest extends TestCase
|
||||
/**
|
||||
* @dataProvider flattenDataProvider
|
||||
*/
|
||||
public function testPrevious(\Exception $exception, $statusCode)
|
||||
public function testPrevious(\Exception $exception)
|
||||
{
|
||||
$flattened = FlattenException::create($exception);
|
||||
$flattened2 = FlattenException::create($exception);
|
||||
@@ -167,7 +173,7 @@ class FlattenExceptionTest extends TestCase
|
||||
/**
|
||||
* @dataProvider flattenDataProvider
|
||||
*/
|
||||
public function testToArray(\Exception $exception, $statusCode)
|
||||
public function testToArray(\Exception $exception)
|
||||
{
|
||||
$flattened = FlattenException::create($exception);
|
||||
$flattened->setTrace(array(), 'foo.php', 123);
|
||||
@@ -187,7 +193,7 @@ class FlattenExceptionTest extends TestCase
|
||||
public function flattenDataProvider()
|
||||
{
|
||||
return array(
|
||||
array(new \Exception('test', 123), 500),
|
||||
array(new \Exception('test', 123)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -230,7 +236,7 @@ class FlattenExceptionTest extends TestCase
|
||||
$this->assertSame(array('object', 'stdClass'), $array[$i++]);
|
||||
$this->assertSame(array('object', 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException'), $array[$i++]);
|
||||
$this->assertSame(array('incomplete-object', 'BogusTestClass'), $array[$i++]);
|
||||
$this->assertSame(array('resource', defined('HHVM_VERSION') ? 'Directory' : 'stream'), $array[$i++]);
|
||||
$this->assertSame(array('resource', \defined('HHVM_VERSION') ? 'Directory' : 'stream'), $array[$i++]);
|
||||
$this->assertSame(array('resource', 'stream'), $array[$i++]);
|
||||
|
||||
$args = $array[$i++];
|
||||
@@ -255,6 +261,7 @@ class FlattenExceptionTest extends TestCase
|
||||
|
||||
public function testRecursionInArguments()
|
||||
{
|
||||
$a = null;
|
||||
$a = array('foo', array(2, &$a));
|
||||
$exception = $this->createException($a);
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
namespace Symfony\Component\Debug\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Debug\ExceptionHandler;
|
||||
use Symfony\Component\Debug\Exception\OutOfMemoryException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Debug\ExceptionHandler;
|
||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
require_once __DIR__.'/HeaderMock.php';
|
||||
|
||||
@@ -39,8 +39,8 @@ class ExceptionHandlerTest extends TestCase
|
||||
$handler->sendPhpResponse(new \RuntimeException('Foo'));
|
||||
$response = ob_get_clean();
|
||||
|
||||
$this->assertContains('<h1>Whoops, looks like something went wrong.</h1>', $response);
|
||||
$this->assertNotContains('<h2 class="block_exception clear_fix">', $response);
|
||||
$this->assertContains('Whoops, looks like something went wrong.', $response);
|
||||
$this->assertNotContains('<div class="trace trace-as-html">', $response);
|
||||
|
||||
$handler = new ExceptionHandler(true);
|
||||
|
||||
@@ -48,8 +48,8 @@ class ExceptionHandlerTest extends TestCase
|
||||
$handler->sendPhpResponse(new \RuntimeException('Foo'));
|
||||
$response = ob_get_clean();
|
||||
|
||||
$this->assertContains('<h1>Whoops, looks like something went wrong.</h1>', $response);
|
||||
$this->assertContains('<h2 class="block_exception clear_fix">', $response);
|
||||
$this->assertContains('Whoops, looks like something went wrong.', $response);
|
||||
$this->assertContains('<div class="trace trace-as-html">', $response);
|
||||
}
|
||||
|
||||
public function testStatusCode()
|
||||
@@ -94,7 +94,7 @@ class ExceptionHandlerTest extends TestCase
|
||||
$handler->sendPhpResponse(new \RuntimeException('Foo', 0, new \RuntimeException('Bar')));
|
||||
$response = ob_get_clean();
|
||||
|
||||
$this->assertStringMatchesFormat('%A<span class="exception_message">Foo</span>%A<span class="exception_message">Bar</span>%A', $response);
|
||||
$this->assertStringMatchesFormat('%A<p class="break-long-words trace-message">Foo</p>%A<p class="break-long-words trace-message">Bar</p>%A', $response);
|
||||
}
|
||||
|
||||
public function testHandle()
|
||||
|
||||
@@ -11,19 +11,18 @@
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\FatalErrorHandler;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
|
||||
use Symfony\Component\Debug\DebugClassLoader;
|
||||
use Composer\Autoload\ClassLoader as ComposerClassLoader;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Debug\DebugClassLoader;
|
||||
use Symfony\Component\Debug\Exception\FatalErrorException;
|
||||
use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
|
||||
|
||||
class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
{
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
foreach (spl_autoload_functions() as $function) {
|
||||
if (!is_array($function)) {
|
||||
if (!\is_array($function)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -33,7 +32,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
}
|
||||
|
||||
if ($function[0] instanceof ComposerClassLoader) {
|
||||
$function[0]->add('Symfony_Component_Debug_Tests_Fixtures', dirname(dirname(dirname(dirname(dirname(__DIR__))))));
|
||||
$function[0]->add('Symfony_Component_Debug_Tests_Fixtures', \dirname(\dirname(\dirname(\dirname(\dirname(__DIR__))))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -70,12 +69,10 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
|
||||
public function provideClassNotFoundData()
|
||||
{
|
||||
$prefixes = array('Symfony\Component\Debug\Exception\\' => realpath(__DIR__.'/../../Exception'));
|
||||
$autoloader = new ComposerClassLoader();
|
||||
$autoloader->add('Symfony\Component\Debug\Exception\\', realpath(__DIR__.'/../../Exception'));
|
||||
|
||||
$symfonyAutoloader = new SymfonyClassLoader();
|
||||
$symfonyAutoloader->addPrefixes($prefixes);
|
||||
|
||||
$debugClassLoader = new DebugClassLoader(array($symfonyAutoloader, 'loadClass'));
|
||||
$debugClassLoader = new DebugClassLoader(array($autoloader, 'loadClass'));
|
||||
|
||||
return array(
|
||||
array(
|
||||
@@ -131,7 +128,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
|
||||
),
|
||||
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
|
||||
array($symfonyAutoloader, 'loadClass'),
|
||||
array($autoloader, 'loadClass'),
|
||||
),
|
||||
array(
|
||||
array(
|
||||
|
||||
@@ -64,10 +64,10 @@ class UndefinedMethodFatalErrorHandlerTest extends TestCase
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'type' => 1,
|
||||
'message' => 'Call to undefined method class@anonymous::test()',
|
||||
'file' => '/home/possum/work/symfony/test.php',
|
||||
'line' => 11,
|
||||
'type' => 1,
|
||||
'message' => 'Call to undefined method class@anonymous::test()',
|
||||
'file' => '/home/possum/work/symfony/test.php',
|
||||
'line' => 11,
|
||||
),
|
||||
'Attempted to call an undefined method named "test" of class "class@anonymous".',
|
||||
),
|
||||
|
||||
13
Tests/Fixtures/AnnotatedClass.php
Normal file
13
Tests/Fixtures/AnnotatedClass.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
class AnnotatedClass
|
||||
{
|
||||
/**
|
||||
* @deprecated since version 3.4.
|
||||
*/
|
||||
public function deprecatedMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
/**
|
||||
* @deprecated but this is a test
|
||||
* deprecation notice.
|
||||
* deprecation notice
|
||||
* @foobar
|
||||
*/
|
||||
class DeprecatedClass
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
/**
|
||||
* @deprecated but this is a test
|
||||
* deprecation notice.
|
||||
* deprecation notice
|
||||
* @foobar
|
||||
*/
|
||||
interface DeprecatedInterface
|
||||
|
||||
19
Tests/Fixtures/ExtendedFinalMethod.php
Normal file
19
Tests/Fixtures/ExtendedFinalMethod.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
class ExtendedFinalMethod extends FinalMethod
|
||||
{
|
||||
use FinalMethod2Trait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function finalMethod()
|
||||
{
|
||||
}
|
||||
|
||||
public function anotherMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
10
Tests/Fixtures/FinalClass.php
Normal file
10
Tests/Fixtures/FinalClass.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
/**
|
||||
* @final since version 3.3.
|
||||
*/
|
||||
class FinalClass
|
||||
{
|
||||
}
|
||||
24
Tests/Fixtures/FinalMethod.php
Normal file
24
Tests/Fixtures/FinalMethod.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
class FinalMethod
|
||||
{
|
||||
/**
|
||||
* @final since version 3.3.
|
||||
*/
|
||||
public function finalMethod()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @final
|
||||
*/
|
||||
public function finalMethod2()
|
||||
{
|
||||
}
|
||||
|
||||
public function anotherMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
10
Tests/Fixtures/FinalMethod2Trait.php
Normal file
10
Tests/Fixtures/FinalMethod2Trait.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
trait FinalMethod2Trait
|
||||
{
|
||||
public function finalMethod2()
|
||||
{
|
||||
}
|
||||
}
|
||||
15
Tests/Fixtures/InternalClass.php
Normal file
15
Tests/Fixtures/InternalClass.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
/**
|
||||
* @internal since version 3.4.
|
||||
*/
|
||||
class InternalClass
|
||||
{
|
||||
use InternalTrait2;
|
||||
|
||||
public function usedInInternalClass()
|
||||
{
|
||||
}
|
||||
}
|
||||
10
Tests/Fixtures/InternalInterface.php
Normal file
10
Tests/Fixtures/InternalInterface.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface InternalInterface
|
||||
{
|
||||
}
|
||||
10
Tests/Fixtures/InternalTrait.php
Normal file
10
Tests/Fixtures/InternalTrait.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait InternalTrait
|
||||
{
|
||||
}
|
||||
23
Tests/Fixtures/InternalTrait2.php
Normal file
23
Tests/Fixtures/InternalTrait2.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait InternalTrait2
|
||||
{
|
||||
/**
|
||||
* @internal since version 3.4
|
||||
*/
|
||||
public function internalMethod()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal but should not trigger a deprecation
|
||||
*/
|
||||
public function usedInInternalClass()
|
||||
{
|
||||
}
|
||||
}
|
||||
3
Tests/Fixtures/Throwing.php
Normal file
3
Tests/Fixtures/Throwing.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
throw new \Exception('boo');
|
||||
13
Tests/Fixtures/TraitWithInternalMethod.php
Normal file
13
Tests/Fixtures/TraitWithInternalMethod.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
trait TraitWithInternalMethod
|
||||
{
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function foo()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -27,12 +27,12 @@ function testHeader()
|
||||
{
|
||||
static $headers = array();
|
||||
|
||||
if (!$h = func_get_args()) {
|
||||
if (!$h = \func_get_args()) {
|
||||
$h = $headers;
|
||||
$headers = array();
|
||||
|
||||
return $h;
|
||||
}
|
||||
|
||||
$headers[] = func_get_args();
|
||||
$headers[] = \func_get_args();
|
||||
}
|
||||
|
||||
27
Tests/phpt/debug_class_loader.phpt
Normal file
27
Tests/phpt/debug_class_loader.phpt
Normal file
@@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
Test DebugClassLoader with previously loaded parents
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||
|
||||
use Symfony\Component\Debug\DebugClassLoader;
|
||||
|
||||
$vendor = __DIR__;
|
||||
while (!file_exists($vendor.'/vendor')) {
|
||||
$vendor = \dirname($vendor);
|
||||
}
|
||||
require $vendor.'/vendor/autoload.php';
|
||||
|
||||
class_exists(FinalMethod::class);
|
||||
|
||||
set_error_handler(function ($type, $msg) { echo $msg, "\n"; });
|
||||
|
||||
DebugClassLoader::enable();
|
||||
|
||||
class_exists(ExtendedFinalMethod::class);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" method is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".
|
||||
The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod2()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".
|
||||
46
Tests/phpt/decorate_exception_hander.phpt
Normal file
46
Tests/phpt/decorate_exception_hander.phpt
Normal file
@@ -0,0 +1,46 @@
|
||||
--TEST--
|
||||
Test catching fatal errors when handlers are nested
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug;
|
||||
|
||||
$vendor = __DIR__;
|
||||
while (!file_exists($vendor.'/vendor')) {
|
||||
$vendor = \dirname($vendor);
|
||||
}
|
||||
require $vendor.'/vendor/autoload.php';
|
||||
|
||||
set_error_handler('var_dump');
|
||||
set_exception_handler('var_dump');
|
||||
|
||||
ErrorHandler::register(null, false);
|
||||
|
||||
if (true) {
|
||||
class foo extends missing
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Class 'Symfony\Component\Debug\missing' not found in %s on line %d
|
||||
object(Symfony\Component\Debug\Exception\ClassNotFoundException)#%d (8) {
|
||||
["message":protected]=>
|
||||
string(131) "Attempted to load class "missing" from namespace "Symfony\Component\Debug".
|
||||
Did you forget a "use" statement for another namespace?"
|
||||
["string":"Exception":private]=>
|
||||
string(0) ""
|
||||
["code":protected]=>
|
||||
int(0)
|
||||
["file":protected]=>
|
||||
string(%d) "%s"
|
||||
["line":protected]=>
|
||||
int(%d)
|
||||
["trace":"Exception":private]=>
|
||||
array(%d) {%A}
|
||||
["previous":"Exception":private]=>
|
||||
NULL
|
||||
["severity":protected]=>
|
||||
int(1)
|
||||
}
|
||||
35
Tests/phpt/exception_rethrown.phpt
Normal file
35
Tests/phpt/exception_rethrown.phpt
Normal file
@@ -0,0 +1,35 @@
|
||||
--TEST--
|
||||
Test rethrowing in custom exception handler
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug;
|
||||
|
||||
$vendor = __DIR__;
|
||||
while (!file_exists($vendor.'/vendor')) {
|
||||
$vendor = \dirname($vendor);
|
||||
}
|
||||
require $vendor.'/vendor/autoload.php';
|
||||
|
||||
if (true) {
|
||||
class TestLogger extends \Psr\Log\AbstractLogger
|
||||
{
|
||||
public function log($level, $message, array $context = array())
|
||||
{
|
||||
echo $message, "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_exception_handler(function ($e) { echo 123; throw $e; });
|
||||
ErrorHandler::register()->setDefaultLogger(new TestLogger());
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
throw new \Exception('foo');
|
||||
?>
|
||||
--EXPECTF--
|
||||
Uncaught Exception: foo
|
||||
123
|
||||
Fatal error: Uncaught %s:25
|
||||
Stack trace:
|
||||
%a
|
||||
42
Tests/phpt/fatal_with_nested_handlers.phpt
Normal file
42
Tests/phpt/fatal_with_nested_handlers.phpt
Normal file
@@ -0,0 +1,42 @@
|
||||
--TEST--
|
||||
Test catching fatal errors when handlers are nested
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Debug;
|
||||
|
||||
$vendor = __DIR__;
|
||||
while (!file_exists($vendor.'/vendor')) {
|
||||
$vendor = \dirname($vendor);
|
||||
}
|
||||
require $vendor.'/vendor/autoload.php';
|
||||
|
||||
Debug::enable();
|
||||
ini_set('display_errors', 0);
|
||||
|
||||
$eHandler = set_error_handler('var_dump');
|
||||
$xHandler = set_exception_handler('var_dump');
|
||||
|
||||
var_dump(array(
|
||||
$eHandler[0] === $xHandler[0] ? 'Error and exception handlers do match' : 'Error and exception handlers are different',
|
||||
));
|
||||
|
||||
$eHandler[0]->setExceptionHandler('print_r');
|
||||
|
||||
if (true) {
|
||||
class Broken implements \Serializable
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(37) "Error and exception handlers do match"
|
||||
}
|
||||
object(Symfony\Component\Debug\Exception\FatalErrorException)#%d (%d) {
|
||||
["message":protected]=>
|
||||
string(199) "Error: Class Symfony\Component\Debug\Broken contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (Serializable::serialize, Serializable::unserialize)"
|
||||
%a
|
||||
}
|
||||
@@ -16,15 +16,14 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"php": "^5.5.9|>=7.0.8",
|
||||
"psr/log": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/class-loader": "~2.8|~3.0",
|
||||
"symfony/http-kernel": "~2.8|~3.0"
|
||||
"symfony/http-kernel": "~2.8|~3.0|~4.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Component\\Debug\\": "" },
|
||||
@@ -35,7 +34,7 @@
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.2-dev"
|
||||
"dev-master": "3.4-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user