Compare commits

..

100 Commits

Author SHA1 Message Date
Nicolas Grekas
43ce8ab34c Merge branch '3.4' into 4.2
* 3.4:
  [TwigBridge] remove deprecation triggered when using Twig 2.7
2019-03-10 18:09:50 +01:00
Nicolas Grekas
adbdd5d663 [TwigBridge] remove deprecation triggered when using Twig 2.7 2019-03-10 18:07:42 +01:00
Nicolas Grekas
94eda15aa1 Merge branch '3.4' into 4.2
* 3.4:
  cs fix
  cs fix
  [PHPUnit-Bridge] override some environment variables
  [TwigBridge] Remove use spaceless tag
  [translation] Update defaut format from yml to yaml
  Change default log level for output streams
  update docblock to match the actual behavior
  compatibility with phpunit8
  [Debug][DebugClassLoader] Detect annotations before blank docblock lines on final and internal methods
  Added translations for chineese language.
2019-03-10 11:08:12 +01:00
Thomas Calvet
a5961253fa [Debug][DebugClassLoader] Detect annotations before blank docblock lines on final and internal methods 2019-03-06 15:53:23 +01:00
Fabien Potencier
26bccc04be Merge branch '3.4' into 4.2
* 3.4:
  detect annotations before blank docblock lines
2019-03-04 12:23:00 +01:00
Christian Flothmann
878d05a2eb detect annotations before blank docblock lines 2019-03-04 11:54:25 +01:00
Fabien Potencier
83e5508e9d Merge branch '3.4' into 4.2
* 3.4:
  fixed CS
  removed suggestion
  [PropertyAccess] Fixed PropertyPathBuilder remove that fails to reset internal indexes
  bumped Symfony version to 3.4.24
  updated VERSION for 3.4.23
  update CONTRIBUTORS for 3.4.23
  updated CHANGELOG for 3.4.23
  [Routing][ServiceRouterLoader] Remove an outdated comment
2019-03-04 10:16:25 +01:00
Fabien Potencier
d5f9980171 fixed CS 2019-03-04 10:11:50 +01:00
Fabien Potencier
de73f48977 Merge branch '3.4' into 4.2
* 3.4:
  Removed non-existing parameters for LogoutUrlGenerator calls
  [HttpKernel] Correctly merging cache directives in HttpCache/ResponseCacheStrategy
  [Validator] Add the missing translations for the Latvian ("lv") locale
  Fixed the DebugClassLoader compatibility with eval()'d code on Darwin
  [Validator] Update Serbian translation file
2019-03-03 19:11:24 +01:00
Pascal Luna
8d8a9e877b Fixed the DebugClassLoader compatibility with eval()'d code on Darwin 2019-02-24 16:45:11 +01:00
Nicolas Grekas
9359ad70a1 Merge branch '3.4' into 4.2
* 3.4: (24 commits)
  Apply php-cs-fixer rule for array_key_exists()
  [Security] Change FormAuthenticator if condition
  handles multi-byte characters in autocomplete
  speed up tests running them without debug flag
  [Translations] added missing Croatian validators
  Fix getItems() performance issue with RedisCluster (php-redis)
  [VarDumper] Keep a ref to objects to ensure their handle cannot be reused while cloning
  IntegerType: reject submitted non-integer numbers
  be keen to newcomers
  [HttpKernel] Fix possible infinite loop of exceptions
  fixed CS
  [Validator] Added missing translations for Afrikaans
  do not validate non-submitted form fields in PATCH requests
  Update usage example in ArrayInput doc block.
  [Console] Prevent ArgvInput::getFirstArgument() from returning an option value
  [Validator] Fixed duplicate UUID
  fixed CS
  [EventDispatcher] Fix unknown priority
  Avoid mutating the Finder when building the iterator
  [Validator] Add the missing translations for the Greek (el) locale
  ...
2019-02-23 16:17:42 +01:00
Nicolas Grekas
1fe36a98e2 Apply php-cs-fixer rule for array_key_exists() 2019-02-23 16:06:07 +01:00
Fabien Potencier
945530598e Merge branch '3.4' into 4.2
* 3.4:
  [TwigBridge] Fix test
  Remove unnecessary ProgressBar stdout writes (fixes flickering)
  [Validator] improve translations for albanian ("sq") locale
  [VarDumper] fix serializing Stub instances
  Don't resolve the Deprecation error handler mode until a deprecation is triggered
  bug #30245 fix lost namespace in eval (fizzka)
  [Twig] removed usage of non-namespaced classes
  added missing dot
  Update validators.lt.xlf
  #30172 Add the missing validation translations for the Luxembourgish …
  [Debug][ErrorHandler] Preserve next error handler
2019-02-18 07:49:49 +01:00
Thomas Calvet
8b8b8b7e57 [Debug][ErrorHandler] Preserve next error handler
Co-authored-by: Joe <cuchac@email.cz>
2019-02-16 11:38:56 +01:00
Nicolas Grekas
cf9b2e33f7 Merge branch '4.1' into 4.2
* 4.1:
  [HttpFoundation] Check file exists before unlink
  [Console] Fixed #29835: ConfirmationQuestion with default true for answer '0'
  [Translation] Concatenated translation messages
  [Form] ensure compatibility with older PHPUnit mocks
  [Serializer] Docblock about throwing exceptions on serializer
  [Debug][ErrorHandler] Preserve our error handler when a logger set another one
  [Form] Changed UrlType input type to text when default_protocol is not null
  [Bugfix] MemcachedSessionHandler::close() must close connection
2019-01-25 15:35:16 +01:00
Nicolas Grekas
caf0f3fa57 Merge branch '3.4' into 4.1
* 3.4:
  [HttpFoundation] Check file exists before unlink
  [Console] Fixed #29835: ConfirmationQuestion with default true for answer '0'
  [Translation] Concatenated translation messages
  [Form] ensure compatibility with older PHPUnit mocks
  [Serializer] Docblock about throwing exceptions on serializer
  [Debug][ErrorHandler] Preserve our error handler when a logger set another one
  [Form] Changed UrlType input type to text when default_protocol is not null
  [Bugfix] MemcachedSessionHandler::close() must close connection
2019-01-25 15:34:37 +01:00
Nicolas Grekas
667a26c4dd bug #29869 [Debug][ErrorHandler] Preserve our error handler when a logger sets another one (fancyweb)
This PR was merged into the 3.4 branch.

Discussion
----------

[Debug][ErrorHandler] Preserve our error handler when a logger sets another one

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

When logging errors handled by the `ErrorHandler::handleError()` method, the logger can temporarily set its own custom error handler. This is for example the case of `Monolog` in the `StreamHandler` class (cf ebb804e432/src/Monolog/Handler/StreamHandler.php (L101)).

However, when the previous error handler is restored by the logger, it "skips" the real previous handler (the `ErrorHandler::handleError()` one) in the pile and goes back directly to the one before. I guess this is because the `restore_error_handler()` call is technically done in the error handler itself, so it logically restore it to the one before and not to itself.

Here is an easy small example that shows the PHP behavior : https://3v4l.org/4OZNZ

The only solution I have found to fix it is to set our error handler everytime an error is logged.

Here are the things I discovered while trying to find a cleaner fix :
- Setting the same error handler in the error handler itself doesn't actually add it to the pile. This is why adding a check is useless.
- Checking if the logger modified the error handler is impossible anyway : to get the current error handler, you need to set a new one temporarirly and then revert it. However, when you revert it by calling `restore_error_handler()` you end up having the same problem you are trying to fix...
- Also trying to get the current error handler in the error handler itself will return NULL if it is itself.

Commits
-------

b979fff6b8 [Debug][ErrorHandler] Preserve our error handler when a logger set another one
2019-01-25 11:19:25 +01:00
Nicolas Grekas
7ae7883ea2 Merge branch '4.1' into 4.2
* 4.1:
  Bump phpunit bridge cache id
  [appveyor] fix create-project phpunit
  Fix HttpKernel Debug requirement
  Fix heredoc
  use final annotation to allow mocking the class
  synchronise the form builder docblock
  Grammar fix in exception message
  fix tests
  forward the parse error to the calling code
  [Debug][DebugClassLoader] Match more cases for final, deprecated and internal classes / methods extends
  ensure compatibility with older PHPUnit mocks
  [Security] Do not mix usage of password_*() functions and sodium_*() ones
2019-01-24 22:39:51 +01:00
Nicolas Grekas
4174d02351 Merge branch '3.4' into 4.1
* 3.4:
  Bump phpunit bridge cache id
  [appveyor] fix create-project phpunit
  Fix HttpKernel Debug requirement
  Fix heredoc
  use final annotation to allow mocking the class
  synchronise the form builder docblock
  Grammar fix in exception message
  fix tests
  forward the parse error to the calling code
  [Debug][DebugClassLoader] Match more cases for final, deprecated and internal classes / methods extends
  ensure compatibility with older PHPUnit mocks
  [Security] Do not mix usage of password_*() functions and sodium_*() ones
2019-01-24 22:39:39 +01:00
Thomas Calvet
b624515da8 [Debug][ErrorHandler] Preserve our error handler when a logger set another one 2019-01-24 21:41:57 +01:00
Thomas Calvet
970d9da53e [Debug][DebugClassLoader] Match more cases for final, deprecated and internal classes / methods extends 2019-01-17 18:28:22 +01:00
Fabien Potencier
2e1483cd0d fixed CS 2019-01-16 22:31:25 +01:00
Fabien Potencier
f6bdc0a7df fixed CS 2019-01-16 21:35:37 +01:00
Fabien Potencier
00db8f8b37 Merge branch '4.1' into 4.2
* 4.1:
  fixed tests
  fixed CS
  fixed CS
  fixed CS
  fixed short array CS in comments
  fixed CS in ExpressionLanguage fixtures
  fixed CS in generated files
  fixed CS on generated container files
  fixed CS on Form PHP templates
  fixed CS on YAML fixtures
  fixed fixtures
  switched array() to []
2019-01-16 21:31:39 +01:00
Fabien Potencier
45c6e7759f fixed CS 2019-01-16 20:07:26 +01:00
Fabien Potencier
d1815d4beb fixed CS 2019-01-16 19:35:49 +01:00
Fabien Potencier
8747fd01a7 Merge branch '3.4' into 4.1
* 3.4:
  fixed CS
  fixed short array CS in comments
  fixed CS in ExpressionLanguage fixtures
  fixed CS in generated files
  fixed CS on generated container files
  fixed CS on Form PHP templates
  fixed CS on YAML fixtures
  fixed fixtures
  switched array() to []
2019-01-16 19:21:11 +01:00
Fabien Potencier
2574a83be3 fixed short array CS in comments 2019-01-16 14:27:11 +01:00
Fabien Potencier
4d92150508 switched array() to [] 2019-01-16 10:39:14 +01:00
Fabien Potencier
1a53cddc50 Merge branch '4.1' into 4.2
* 4.1:
  bump required Twig version
  fix compatibility with Twig >= 2.6.1
  [Form] SA fix
  fix compatibility with PHPUnit 4.8
  remove return type hint for PHP 5 compatibility
  SCA: minor code tweaks
  Component CssSelector tests
  [DebugClassLoader] Readd findFile() method
  [Console] Fix composer.json suggest/provide
  Revert "bug #29597 [DI] fix reporting bindings on overriden services as unused (nicolas-grekas)"
  Fixed exception wording
  Fix SwiftMailerHandler to support Monolog's latest reset functionality
2019-01-14 16:33:52 +01:00
Christian Flothmann
ab51c79f5e Merge branch '3.4' into 4.1
* 3.4:
  fix compatibility with Twig >= 2.6.1
  [Form] SA fix
  fix compatibility with PHPUnit 4.8
  remove return type hint for PHP 5 compatibility
  Component CssSelector tests
  [DebugClassLoader] Readd findFile() method
  [Console] Fix composer.json suggest/provide
  Revert "bug #29597 [DI] fix reporting bindings on overriden services as unused (nicolas-grekas)"
  Fixed exception wording
  Fix SwiftMailerHandler to support Monolog's latest reset functionality
2019-01-14 12:04:47 +01:00
Christian Flothmann
5ca61fb12e remove return type hint for PHP 5 compatibility 2019-01-14 09:43:48 +01:00
Thomas Calvet
ce763d24ed [DebugClassLoader] Readd findFile() method 2019-01-13 17:36:47 +01:00
Christian Flothmann
64cb33c81e Merge branch '4.1' into 4.2
* 4.1:
  Fix: Adjust DocBlock
  \"ParserTest->getParserTestData()\" -> only some more tests
  access the container getting it from the kernel
  [Lock] Pedantic improvements for lock
  [EventDispatcher] Fixed phpdoc on interface
  update year in license files
  [Console] Fix help text for single command applications
  Fix random test failure on lock
  improve error message when using test client without the BrowserKit component
  [Event Dispatcher] fixed 29703: TraceableEventDispatcher reset now sets callStack to null with test to dispatch after reset.
  Fixed minor typos
  Fix: Method can also return null
  [Stopwatch] Fixed phpdoc for category name
2019-01-03 10:07:35 +01:00
Christian Flothmann
3ba0dfd9af Merge branch '3.4' into 4.1
* 3.4:
  Fix: Adjust DocBlock
  \"ParserTest->getParserTestData()\" -> only some more tests
  [Lock] Pedantic improvements for lock
  [EventDispatcher] Fixed phpdoc on interface
  update year in license files
  [Console] Fix help text for single command applications
  Fix random test failure on lock
  improve error message when using test client without the BrowserKit component
  [Event Dispatcher] fixed 29703: TraceableEventDispatcher reset now sets callStack to null with test to dispatch after reset.
  Fixed minor typos
  Fix: Method can also return null
  [Stopwatch] Fixed phpdoc for category name
2019-01-03 10:05:57 +01:00
Christian Flothmann
26d7f23b9b update year in license files 2019-01-01 14:45:19 +01:00
Nicolas Grekas
c8e078dd18 Merge branch '4.1' into 4.2
* 4.1:
  Fix typos in doc blocks
  [Debug] ignore underscore vs backslash namespaces in DebugClassLoader
  [TwigBridge][Form] Prevent multiple rendering of form collection prototypes
  [FrameworkBundle] fix describing routes with no controllers
  [DI] move RegisterServiceSubscribersPass before DecoratorServicePass
  Update ValidationListener.php
  [Yaml] ensures that the mb_internal_encoding is reset to its initial value
  [WebLink] Fixed documentation link
  [Security] getTargetPath of TargetPathTrait must return string or null
  [Hackday][Serializer] Deserialization ignores argument type hint from phpdoc for array in constructor argument
  Optimize perf by replacing call_user_func with dynamic vars
  [Routing] fix dumping same-path routes with placeholders
  [Security] defer log message in guard authenticator
  [Validator] Added IBAN format for Vatican City State
  merge conflicts
  filter out invalid Intl values
  filter out invalid language values
  [Validator] Fixed grouped composite constraints
  [Form] Filter arrays out of scalar form types
  Fix HeaderBag::get phpdoc
2018-12-13 13:39:50 +01:00
Nicolas Grekas
e9c81d5231 Merge branch '3.4' into 4.1
* 3.4:
  [Debug] ignore underscore vs backslash namespaces in DebugClassLoader
  [TwigBridge][Form] Prevent multiple rendering of form collection prototypes
  [FrameworkBundle] fix describing routes with no controllers
  [DI] move RegisterServiceSubscribersPass before DecoratorServicePass
  Update ValidationListener.php
  [Yaml] ensures that the mb_internal_encoding is reset to its initial value
  [WebLink] Fixed documentation link
  [Security] getTargetPath of TargetPathTrait must return string or null
  [Hackday][Serializer] Deserialization ignores argument type hint from phpdoc for array in constructor argument
  [Security] defer log message in guard authenticator
  merge conflicts
  Fix HeaderBag::get phpdoc
2018-12-13 13:30:33 +01:00
Nicolas Grekas
6eb115e3a5 [Debug] ignore underscore vs backslash namespaces in DebugClassLoader 2018-12-12 21:57:22 +01:00
Gabriel Ostrolucký
26bd579e62 Optimize perf by replacing call_user_func with dynamic vars 2018-12-09 23:58:21 +01:00
Nicolas Grekas
e0a2b92ee0 Merge branch '4.1' into 4.2
* 4.1:
  [DI] fix combinatorial explosion when analyzing the service graph
  [Debug] workaround opcache bug mutating "$this" !?!
2018-11-28 19:24:18 +01:00
Nicolas Grekas
533c656e12 Merge branch '3.4' into 4.1
* 3.4:
  [DI] fix combinatorial explosion when analyzing the service graph
  [Debug] workaround opcache bug mutating "$this" !?!
2018-11-28 19:21:59 +01:00
Nicolas Grekas
a2233f555d [Debug] workaround opcache bug mutating "$this" !?! 2018-11-27 13:43:10 +01:00
Nicolas Grekas
7a8a60421b [Debug][HttpKernel] remove frames added by DebugClassLoader in stack traces 2018-11-13 20:31:34 +01:00
Nicolas Grekas
0aae90af4e Merge branch '4.1'
* 4.1:
  [Form] Hardened test suite for empty data
  Bump phpunit XSD version to 5.2
  [Fwb][EventDispatcher][HttpKernel] Fix getClosureScopeClass usage to describe callables
  Add required key attribute
2018-11-11 20:52:12 +01:00
Nicolas Grekas
f9eea0cff9 Merge branch '3.4' into 4.1
* 3.4:
  [Form] Hardened test suite for empty data
  Bump phpunit XSD version to 5.2
  [Fwb][EventDispatcher][HttpKernel] Fix getClosureScopeClass usage to describe callables
  Add required key attribute
2018-11-11 20:51:29 +01:00
Nicolas Grekas
2016b3eec2 Merge branch '2.8' into 3.4
* 2.8:
  [Form] Hardened test suite for empty data
  Bump phpunit XSD version to 5.2
  Add required key attribute
2018-11-11 20:48:54 +01:00
Grégoire Paris
74251c8d50 Bump phpunit XSD version to 5.2
Some attributes being used in the phpunit configuration files, namely
failOnRisky and failOnWarning were introduced in phpunit 5.2.0. The
Composer configuration shows that tests should run with old versions of
phpunit, but phpunit only validates the configuration against the XSD
since phpunit 7.2.0.
These changes can be tested as follows:

wget http://schema.phpunit.de/5.2/phpunit.xsd
xargs xmllint --schema phpunit.xsd  1>/dev/null
find src -name phpunit.xml.dist| xargs xmllint --schema phpunit.xsd  1>/dev/null

See 7e06a82806
See 46e3745a03/composer.json (L98)
2018-11-11 12:18:13 +01:00
Nicolas Grekas
85c1365d7a Merge branch '4.1'
* 4.1:
  Fixed typo
  Fix ini_get() for boolean values
  SCA: fixed broken tests
  SCA: applied code style as per guidelines
  SCA: minor code tweaks
2018-10-31 10:23:02 +01:00
Nicolas Grekas
19090917b8 Merge branch '3.4' into 4.1
* 3.4:
  Fixed typo
  Fix ini_get() for boolean values
  SCA: fixed broken tests
  SCA: applied code style as per guidelines
  SCA: minor code tweaks
2018-10-31 10:09:42 +01:00
Nicolas Grekas
fe9793af00 Merge branch '2.8' into 3.4
* 2.8:
  Fixed typo
  Fix ini_get() for boolean values
2018-10-31 10:06:03 +01:00
François-Xavier de Guillebon
6a198c52b6 Fix ini_get() for boolean values 2018-10-30 17:24:01 +01:00
Nicolas Grekas
e72d01486a Merge branch '4.1'
* 4.1:
  CS fix
  [Debug] fix compat with PHP 7.3
2018-10-02 18:38:08 +02:00
Nicolas Grekas
e3f76ce619 Merge branch '3.4' into 4.1
* 3.4:
  CS fix
  [Debug] fix compat with PHP 7.3
2018-10-02 18:36:10 +02:00
Nicolas Grekas
0a612e9dfb Merge branch '2.8' into 3.4
* 2.8:
  CS fix
  [Debug] fix compat with PHP 7.3
2018-10-02 18:33:53 +02:00
Nicolas Grekas
087890e02f [Debug] fix compat with PHP 7.3 2018-10-02 18:22:14 +02:00
Gabriel Caruso
65d41d1696 [CS] Enforces null type hint on last position in phpDocs 2018-10-02 00:12:00 -03:00
Nicolas Grekas
92320d007e Merge branch '4.1'
* 4.1:
  [Debug] Fix false-positive "MicroKernelTrait::loadRoutes()" method is considered internal"
  [Console] Fixed boxed table style with colspan
  parse numbers terminated with decimal separator
  fail reverse transforming invalid RFC 3339 dates
2018-09-22 22:55:36 +02:00
Nicolas Grekas
b4a0b67dee Merge branch '3.4' into 4.1
* 3.4:
  [Debug] Fix false-positive "MicroKernelTrait::loadRoutes()" method is considered internal"
  [Console] Fixed boxed table style with colspan
  parse numbers terminated with decimal separator
  fail reverse transforming invalid RFC 3339 dates
2018-09-22 21:04:12 +02:00
Nicolas Grekas
b70cfaae39 [Debug] Fix false-positive "MicroKernelTrait::loadRoutes()" method is considered internal" 2018-09-22 20:25:03 +02:00
Nicolas Grekas
0a6c85e5c6 feature #28329 [Debug] Trigger a deprecation for new parameters not defined in sub classes (GuilhemN)
This PR was merged into the 4.2-dev branch.

Discussion
----------

[Debug] Trigger a deprecation for new parameters not defined in sub classes

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | https://github.com/symfony/symfony/pull/28316
| License       | MIT
| Doc PR        | -

I'm not sure the way https://github.com/symfony/symfony/pull/28316 is implemented is the best so here is an alternative.
Instead of counting on a call from the child method, it uses the `DebugClassLoader` and `@param` annotations. If a `@param` annotation is used on a parent but is then not actually implemented in the child class, a deprecation will be thrown.

Example:
```php
class ClassWithAnnotatedParameters
{
    /**
     * @param string $foo This is a foo parameter.
     */
    public function fooMethod(string $foo)
    {
    }

    /**
     * @param string $bar parameter not implemented yet
     */
    public function barMethod(/** string $bar = null */)
    {
    }

    /**
     * @param Quz $quz parameter not implemented yet
     */
    public function quzMethod(/** Quz $quz = null */)
    {
    }
}
```

```php
class SubClassWithAnnotatedParameters extends ClassWithAnnotatedParameters {
    public function fooMethod(string $foo) { }
    public function barMethod($bar = null) { }
    public function quzMethod() { }
}
```

A deprecation will be triggered because ``SubClassWithAnnotatedParameters::quzMethod()`` which doesn't definee `$quz`.

Commits
-------

1f5d8b62f7 [Debug] Trigger a deprecation for new parameters not defined in sub classes
2018-09-21 18:04:38 +02:00
Guilhem Niot
8f69eb64e4 [Debug] Trigger a deprecation for new parameters not defined in sub classes 2018-09-21 17:50:51 +02:00
Nicolas Grekas
acb9e69323 Merge branch '4.1'
* 4.1:
  Fix CS
  Allow reuse of Session between requests
  [MonologBridge] Re-add option option to ignore empty context and extra data
  [Lock] remove useless code
  [PhpUnitBridge] fix disabling DeprecationErrorHandler using phpunit.xml file
  Provide debug_backtrace with proper args
  [DI] fix infinite loop involving self-references in decorated services
  forward false label option to nested types
  [DI] fix dumping lazy services
  forward the invalid_message option in date types
2018-09-21 14:51:02 +02:00
Nicolas Grekas
a037ae518a Merge branch '3.4' into 4.1
* 3.4:
  Fix CS
  Allow reuse of Session between requests
  [MonologBridge] Re-add option option to ignore empty context and extra data
  [Lock] remove useless code
  [PhpUnitBridge] fix disabling DeprecationErrorHandler using phpunit.xml file
  Provide debug_backtrace with proper args
  [DI] fix infinite loop involving self-references in decorated services
  forward false label option to nested types
  forward the invalid_message option in date types
2018-09-21 14:49:42 +02:00
Nicolas Grekas
d7b459ba7b Merge branch '2.8' into 3.4
* 2.8:
  Fix CS
  Allow reuse of Session between requests
  Provide debug_backtrace with proper args
  forward false label option to nested types
  forward the invalid_message option in date types
2018-09-21 14:47:54 +02:00
Nicolas Grekas
4fd77efcd4 Fix CS 2018-09-21 14:46:38 +02:00
Nicolas Grekas
9374383ad2 Merge branch '4.1'
* 4.1:
  [Debug] fix detecting overriden final/internal methods implemented using traits
  [Controller][ServiceValueResolver] Making method access case insensitive
2018-09-09 11:23:23 +02:00
Nicolas Grekas
ede2c4b8fd Merge branch '3.4' into 4.1
* 3.4:
  [Debug] fix detecting overriden final/internal methods implemented using traits
  [Controller][ServiceValueResolver] Making method access case insensitive
2018-09-09 11:23:09 +02:00
Nicolas Grekas
87cecce74b [Debug] fix detecting overriden final/internal methods implemented using traits 2018-09-09 11:07:24 +02:00
Nicolas Grekas
42bdc01d61 Improve support for anonymous classes 2018-08-21 14:03:16 +02:00
Nicolas Grekas
e2b31a5a23 Merge branch '4.1'
* 4.1:
  [travis] fix CI for sigchild+Process
  fix merge
  [travis] merge "same Symfony version" jobs in one
  fix merge
  🐛 Fix typo
  Remove the Expires header when calling Response::expire()
  Allow multidimensional collection in property info
  Allow multidimensional collection in property info
2018-08-03 13:20:06 +02:00
Nicolas Grekas
47ead688f1 Merge branch '3.4' into 4.1
* 3.4:
  [travis] fix CI for sigchild+Process
  fix merge
  [travis] merge "same Symfony version" jobs in one
  fix merge
  Remove the Expires header when calling Response::expire()
  Allow multidimensional collection in property info
  Allow multidimensional collection in property info
2018-08-03 13:13:38 +02:00
Nicolas Grekas
c4625e7534 Merge branch '2.8' into 3.4
* 2.8:
  [travis] merge "same Symfony version" jobs in one
2018-08-03 12:42:44 +02:00
Nicolas Grekas
cbb8a5f212 [travis] merge "same Symfony version" jobs in one 2018-08-03 11:45:57 +02:00
Nicolas Grekas
c16ccd52db Merge branch '4.1'
* 4.1:
  Enable native_constant_invocation CS fixer
2018-07-26 13:25:51 +02:00
Nicolas Grekas
9316545571 Merge branch '4.0' into 4.1
* 4.0:
  Enable native_constant_invocation CS fixer
2018-07-26 13:24:31 +02:00
Nicolas Grekas
8d5462cfbc Merge branch '3.4' into 4.0
* 3.4:
  Enable native_constant_invocation CS fixer
2018-07-26 13:22:46 +02:00
Nicolas Grekas
d5a058ff6e Merge branch '2.8' into 3.4
* 2.8:
  Enable native_constant_invocation CS fixer
2018-07-26 13:19:56 +02:00
Nicolas Grekas
d985c8546d Enable native_constant_invocation CS fixer 2018-07-26 13:13:39 +02:00
Nicolas Grekas
32023e0ffa Merge branch '4.1'
* 4.1:
  Alpha-ordering for "use" statements
2018-07-26 11:13:01 +02:00
Nicolas Grekas
38b2f7a11a Merge branch '4.0' into 4.1
* 4.0:
  Alpha-ordering for "use" statements
2018-07-26 11:10:45 +02:00
Nicolas Grekas
eba30e3a78 Merge branch '3.4' into 4.0
* 3.4:
  Alpha-ordering for "use" statements
2018-07-26 11:08:35 +02:00
Nicolas Grekas
13041d84e3 Merge branch '2.8' into 3.4
* 2.8:
  Alpha-ordering for "use" statements
2018-07-26 11:06:28 +02:00
Nicolas Grekas
2f42aa269a Alpha-ordering for "use" statements 2018-07-26 11:03:18 +02:00
Nicolas Grekas
056f617413 Merge branch '4.1'
* 4.1:
  Fix Clidumper tests
  Enable the fixer enforcing fully-qualified calls for compiler-optimized functions
  Apply fixers
  Disable the native_constant_invocation fixer until it can be scoped
  Update the list of excluded files for the CS fixer
2018-07-26 10:59:12 +02:00
Nicolas Grekas
fa0b714b55 Merge branch '4.0' into 4.1
* 4.0:
  Fix Clidumper tests
  Enable the fixer enforcing fully-qualified calls for compiler-optimized functions
  Apply fixers
  Disable the native_constant_invocation fixer until it can be scoped
  Update the list of excluded files for the CS fixer
2018-07-26 10:55:25 +02:00
Nicolas Grekas
fce13776fb Merge branch '3.4' into 4.0
* 3.4:
  Fix Clidumper tests
  Enable the fixer enforcing fully-qualified calls for compiler-optimized functions
  Apply fixers
  Disable the native_constant_invocation fixer until it can be scoped
  Update the list of excluded files for the CS fixer
2018-07-26 10:51:09 +02:00
Nicolas Grekas
34bdb1c801 Merge branch '2.8' into 3.4
* 2.8:
  Fix Clidumper tests
  Enable the fixer enforcing fully-qualified calls for compiler-optimized functions
  Apply fixers
  Disable the native_constant_invocation fixer until it can be scoped
  Update the list of excluded files for the CS fixer
2018-07-26 10:45:46 +02:00
Christophe Coevoet
d070fc2e64 Enable the fixer enforcing fully-qualified calls for compiler-optimized functions 2018-07-24 12:05:38 +02:00
Nicolas Grekas
d49a626c51 Merge branch '4.1'
* 4.1:
  [Filesystem] fix lock file mode
  [Console] fix typo in phpdoc
  improve deprecation messages
2018-07-09 15:30:59 +02:00
Christian Flothmann
a1f2118ced improve deprecation messages 2018-07-06 16:52:28 +02:00
Nicolas Grekas
1970189082 Merge branch '4.1'
* 4.1:
  Bump ext-mongodb to 1.5 on Travis
  Redesign the Debug error page in prod
  [DI] fix dumping deprecated service in yaml
  [Serializer] CsvEncoder::AS_COLLECTION_KEY constant
  bumped Symfony version to 4.1.2
  updated VERSION for 4.1.1
  updated CHANGELOG for 4.1.1
  bumped Symfony version to 4.0.13
  updated VERSION for 4.0.12
  updated CHANGELOG for 4.0.12
  bumped Symfony version to 3.4.13
  updated VERSION for 3.4.12
  updated CHANGELOG for 3.4.12
  bumped Symfony version to 2.8.43
  updated VERSION for 2.8.42
  update CONTRIBUTORS for 2.8.42
  updated CHANGELOG for 2.8.42
2018-06-27 23:06:44 +02:00
Nicolas Grekas
46f848122e Merge branch '4.0' into 4.1
* 4.0:
  Bump ext-mongodb to 1.5 on Travis
  Redesign the Debug error page in prod
  [DI] fix dumping deprecated service in yaml
  bumped Symfony version to 4.0.13
  updated VERSION for 4.0.12
  updated CHANGELOG for 4.0.12
  bumped Symfony version to 3.4.13
  updated VERSION for 3.4.12
  updated CHANGELOG for 3.4.12
  bumped Symfony version to 2.8.43
  updated VERSION for 2.8.42
  update CONTRIBUTORS for 2.8.42
  updated CHANGELOG for 2.8.42
2018-06-27 23:05:46 +02:00
Nicolas Grekas
8c2d96aff8 Merge branch '3.4' into 4.0
* 3.4:
  Bump ext-mongodb to 1.5 on Travis
  Redesign the Debug error page in prod
  [DI] fix dumping deprecated service in yaml
  bumped Symfony version to 3.4.13
  updated VERSION for 3.4.12
  updated CHANGELOG for 3.4.12
  bumped Symfony version to 2.8.43
  updated VERSION for 2.8.42
  update CONTRIBUTORS for 2.8.42
  updated CHANGELOG for 2.8.42
2018-06-27 23:04:32 +02:00
Javier Eguiluz
0e3ca9cbde Redesign the Debug error page in prod 2018-06-26 10:45:54 +02:00
Fabien Potencier
47e6788c5b Merge branch '2.8' into 3.4
* 2.8:
  Add note about changed form processing when using PUT requests
  The debug class loader is always loaded by Debug::enable().
  [Intl] Update ICU data to 62.1
2018-06-25 13:10:40 +02:00
Alexander M. Turek
a26ddce7fe The debug class loader is always loaded by Debug::enable(). 2018-06-22 17:01:26 +02:00
Nicolas Grekas
ef8bd62973 Merge branch '4.1'
* 4.1:
  [Cache][Security] Use Throwable where possible
  revert #27545
  Update Finder.php
  [FrameworkBundle] remove dead code in CachePoolClearerPass
  Fix security-core cross-dependencies, fixes #27507
  Pass previous exception to FatalErrorException
2018-06-08 11:40:00 +02:00
Nicolas Grekas
09f5c0938b Merge branch '4.1'
* 4.1: (22 commits)
  Fix CS
  [PropertyInfo] fix resolving parent|self type hints
  fixed CS
  fix merge
  [Security] Fix logout
  Cleanup 2 tests for the HttpException classes
  #27250 limiting GET_LOCK key up to 64 char due to changes in MySQL 5.7.5 and later
  [Config] Fix tests when path contains UTF chars
  [DI] Shared services should not be inlined in non-shared ones
  [Profiler] Remove propel & event_listener_loading category identifiers
  [Filesystem] Fix usages of error_get_last()
  [Cache][Lock] Fix usages of error_get_last()
  [Debug] Fix populating error_get_last() for handled silent errors
  fixed CS
  fixed CS
  fixed CS
  [FrameworkBundle] Fix cache:clear on vagrant
  [HttpKernel] Handle NoConfigurationException "onKernelException()"
  Fix misses calculation when calling getItems
  [DI] Display previous error messages when throwing unused bindings
  ...
2018-05-16 16:42:13 +02:00
Fabien Potencier
feb747f95f updated version to 4.2 2018-05-07 16:51:25 +02:00
40 changed files with 1205 additions and 674 deletions

View File

@@ -20,17 +20,17 @@ use Psr\Log\AbstractLogger;
*/
class BufferingLogger extends AbstractLogger
{
private $logs = array();
private $logs = [];
public function log($level, $message, array $context = array())
public function log($level, $message, array $context = [])
{
$this->logs[] = array($level, $message, $context);
$this->logs[] = [$level, $message, $context];
}
public function cleanLogs()
{
$logs = $this->logs;
$this->logs = array();
$this->logs = [];
return $logs;
}

View File

@@ -42,10 +42,10 @@ class Debug
error_reporting(E_ALL);
}
if (!\in_array(PHP_SAPI, array('cli', 'phpdbg'), true)) {
if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
ini_set('display_errors', 0);
ExceptionHandler::register();
} elseif ($displayErrors && (!ini_get('log_errors') || ini_get('error_log'))) {
} elseif ($displayErrors && (!filter_var(ini_get('log_errors'), FILTER_VALIDATE_BOOLEAN) || ini_get('error_log'))) {
// CLI - display errors only if they're not already logged to STDERR
ini_set('display_errors', 1);
}

View File

@@ -11,6 +11,8 @@
namespace Symfony\Component\Debug;
use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation;
/**
* Autoloader checking if the class is really defined in the file found.
*
@@ -21,29 +23,31 @@ namespace Symfony\Component\Debug;
* @author Fabien Potencier <fabien@symfony.com>
* @author Christophe Coevoet <stof@notk.org>
* @author Nicolas Grekas <p@tchwork.com>
* @author Guilhem Niot <guilhem.niot@gmail.com>
*/
class DebugClassLoader
{
private $classLoader;
private $isFinder;
private $loaded = array();
private $loaded = [];
private static $caseCheck;
private static $checkedClasses = array();
private static $final = array();
private static $finalMethods = array();
private static $deprecated = array();
private static $internal = array();
private static $internalMethods = array();
private static $darwinCache = array('/' => array('/', array()));
private static $checkedClasses = [];
private static $final = [];
private static $finalMethods = [];
private static $deprecated = [];
private static $internal = [];
private static $internalMethods = [];
private static $annotatedParameters = [];
private static $darwinCache = ['/' => ['/', []]];
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 +56,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 +88,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,8 +97,8 @@ class DebugClassLoader
}
foreach ($functions as $function) {
if (!is_array($function) || !$function[0] instanceof self) {
$function = array(new static($function), 'loadClass');
if (!\is_array($function) || !$function[0] instanceof self) {
$function = [new static($function), 'loadClass'];
}
spl_autoload_register($function);
@@ -106,7 +110,7 @@ class DebugClassLoader
*/
public static function disable()
{
if (!is_array($functions = spl_autoload_functions())) {
if (!\is_array($functions = spl_autoload_functions())) {
return;
}
@@ -115,7 +119,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();
}
@@ -123,13 +127,19 @@ class DebugClassLoader
}
}
/**
* @return string|null
*/
public function findFile($class)
{
return $this->isFinder ? $this->classLoader[0]->findFile($class) ?: null : null;
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
*
* @return bool|null True, if loaded
*
* @throws \RuntimeException
*/
public function loadClass($class)
@@ -139,17 +149,17 @@ class DebugClassLoader
try {
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);
if (!$file = $this->classLoader[0]->findFile($class) ?: false) {
// no-op
} elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) {
require $file;
if ($wasCached) {
return;
}
return;
} else {
require $file;
}
} else {
call_user_func($this->classLoader, $class);
($this->classLoader)($class);
$file = false;
}
} finally {
@@ -183,196 +193,266 @@ class DebugClassLoader
throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: "%s" vs "%s".', $class, $name));
}
// Don't trigger deprecations for classes in the same vendor
if (2 > $len = 1 + (\strpos($name, '\\') ?: \strpos($name, '_'))) {
$len = 0;
$ns = '';
$deprecations = $this->checkAnnotations($refl, $name);
foreach ($deprecations as $message) {
@trigger_error($message, E_USER_DEPRECATED);
}
}
if (!$file) {
return;
}
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));
}
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 = [];
// Don't trigger deprecations for classes in the same vendor
if (2 > $len = 1 + (\strpos($class, '\\') ?: \strpos($class, '_'))) {
$len = 0;
$ns = '';
} else {
$ns = \str_replace('_', '\\', \substr($class, 0, $len));
}
// Detect annotations on the class
if (false !== $doc = $refl->getDocComment()) {
foreach (['final', 'deprecated', 'internal'] as $annotation) {
if (false !== \strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) {
self::${$annotation}[$class] = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\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, \str_replace('_', '\\', $use), $len) && !isset(self::$deprecated[$class])) {
$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, \str_replace('_', '\\', $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, @internal and @param annotations for methods
self::$finalMethods[$class] = [];
self::$internalMethods[$class] = [];
self::$annotatedParameters[$class] = [];
foreach ($parentAndOwnInterfaces as $use) {
foreach (['finalMethods', 'internalMethods', 'annotatedParameters'] 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);
}
}
// To read method annotations
$doc = $method->getDocComment();
if (isset(self::$annotatedParameters[$class][$method->name])) {
$definedParameters = [];
foreach ($method->getParameters() as $parameter) {
$definedParameters[$parameter->name] = true;
}
foreach (self::$annotatedParameters[$class][$method->name] as $parameterName => $deprecation) {
if (!isset($definedParameters[$parameterName]) && !($doc && preg_match("/\\n\\s+\\* @param (.*?)(?<= )\\\${$parameterName}\\b/", $doc))) {
$deprecations[] = sprintf($deprecation, $class);
}
}
}
if (!$doc) {
continue;
}
$finalOrInternal = false;
foreach (['final', 'internal'] as $annotation) {
if (false !== \strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) {
$message = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : '';
self::${$annotation.'Methods'}[$class][$method->name] = [$class, $message];
$finalOrInternal = true;
}
}
if ($finalOrInternal || $method->isConstructor() || false === \strpos($doc, '@param') || StatelessInvocation::class === $class) {
continue;
}
if (!preg_match_all('#\n\s+\* @param (.*?)(?<= )\$([a-zA-Z0-9_\x7f-\xff]++)#', $doc, $matches, PREG_SET_ORDER)) {
continue;
}
if (!isset(self::$annotatedParameters[$class][$method->name])) {
$definedParameters = [];
foreach ($method->getParameters() as $parameter) {
$definedParameters[$parameter->name] = true;
}
}
foreach ($matches as list(, $parameterType, $parameterName)) {
if (!isset($definedParameters[$parameterName])) {
$parameterType = trim($parameterType);
self::$annotatedParameters[$class][$method->name][$parameterName] = sprintf('The "%%s::%s()" method will require a new "%s$%s" argument in the next major version of its parent class "%s", not defining it is deprecated.', $method->name, $parameterType ? $parameterType.' ' : '', $parameterName, $method->class);
}
}
}
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 [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 {
$ns = \substr($name, 0, $len);
}
$dir = getcwd();
chdir($real);
$real = getcwd().'/';
chdir($dir);
// 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}[$name] = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : '';
}
}
}
$parentAndTraits = \class_uses($name, false);
if ($parent = \get_parent_class($class)) {
$parentAndTraits[] = $parent;
if (!isset(self::$checkedClasses[$parent])) {
$this->checkClass($parent);
}
if (isset(self::$final[$parent])) {
@trigger_error(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], $name), E_USER_DEPRECATED);
}
}
// Detect if the parent is annotated
foreach ($parentAndTraits + $this->getOwnInterfaces($name, $parent) as $use) {
if (!isset(self::$checkedClasses[$use])) {
$this->checkClass($use);
}
if (isset(self::$deprecated[$use]) && \strncmp($ns, $use, $len)) {
$type = class_exists($name, false) ? 'class' : (interface_exists($name, false) ? 'interface' : 'trait');
$verb = class_exists($use, false) || interface_exists($name, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses');
@trigger_error(sprintf('The "%s" %s %s "%s" that is deprecated%s.', $name, $type, $verb, $use, self::$deprecated[$use]), E_USER_DEPRECATED);
}
if (isset(self::$internal[$use]) && \strncmp($ns, $use, $len)) {
@trigger_error(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], $name), E_USER_DEPRECATED);
}
}
// Inherit @final and @internal annotations for methods
self::$finalMethods[$name] = array();
self::$internalMethods[$name] = array();
foreach ($parentAndTraits as $use) {
foreach (array('finalMethods', 'internalMethods') as $property) {
if (isset(self::${$property}[$use])) {
self::${$property}[$name] = self::${$property}[$name] ? self::${$property}[$use] + self::${$property}[$name] : self::${$property}[$use];
}
}
}
$isClass = \class_exists($name, false);
foreach ($refl->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $method) {
if ($method->class !== $name) {
continue;
}
// Method from a trait
if ($method->getFilename() !== $refl->getFileName()) {
continue;
}
if ($isClass && $parent && isset(self::$finalMethods[$parent][$method->name])) {
list($declaringClass, $message) = self::$finalMethods[$parent][$method->name];
@trigger_error(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, $name), E_USER_DEPRECATED);
}
foreach ($parentAndTraits as $use) {
if (isset(self::$internalMethods[$use][$method->name])) {
list($declaringClass, $message) = self::$internalMethods[$use][$method->name];
if (\strncmp($ns, $declaringClass, $len)) {
@trigger_error(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, $name), E_USER_DEPRECATED);
}
}
}
// 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'}[$name][$method->name] = array($name, $message);
$dir = $real;
$k = $kDir;
$i = \strlen($dir) - 1;
while (!isset(self::$darwinCache[$k])) {
self::$darwinCache[$k] = [$dir, []];
self::$darwinCache[$dir] = &self::$darwinCache[$k];
while ('/' !== $dir[--$i]) {
}
$k = substr($k, 0, ++$i);
$dir = substr($dir, 0, $i--);
}
}
}
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));
}
$dirFiles = self::$darwinCache[$kDir][1];
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 (!isset($dirFiles[$file]) && ') : eval()\'d code' === substr($file, -17)) {
// Get the file name from "file_name.php(123) : eval()'d code"
$file = substr($file, 0, strrpos($file, '(', -17));
}
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];
}
/**

View File

@@ -11,16 +11,17 @@
namespace Symfony\Component\Debug;
use Psr\Log\LogLevel;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Symfony\Component\Debug\Exception\FatalErrorException;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\Debug\Exception\FlattenException;
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.
@@ -47,7 +48,7 @@ use Symfony\Component\Debug\FatalErrorHandler\FatalErrorHandlerInterface;
*/
class ErrorHandler
{
private $levels = array(
private $levels = [
E_DEPRECATED => 'Deprecated',
E_USER_DEPRECATED => 'User Deprecated',
E_NOTICE => 'Notice',
@@ -63,25 +64,25 @@ class ErrorHandler
E_PARSE => 'Parse Error',
E_ERROR => 'Error',
E_CORE_ERROR => 'Core Error',
);
];
private $loggers = array(
E_DEPRECATED => array(null, LogLevel::INFO),
E_USER_DEPRECATED => array(null, LogLevel::INFO),
E_NOTICE => array(null, LogLevel::WARNING),
E_USER_NOTICE => array(null, LogLevel::WARNING),
E_STRICT => array(null, LogLevel::WARNING),
E_WARNING => array(null, LogLevel::WARNING),
E_USER_WARNING => array(null, LogLevel::WARNING),
E_COMPILE_WARNING => array(null, LogLevel::WARNING),
E_CORE_WARNING => array(null, LogLevel::WARNING),
E_USER_ERROR => array(null, LogLevel::CRITICAL),
E_RECOVERABLE_ERROR => array(null, LogLevel::CRITICAL),
E_COMPILE_ERROR => array(null, LogLevel::CRITICAL),
E_PARSE => array(null, LogLevel::CRITICAL),
E_ERROR => array(null, LogLevel::CRITICAL),
E_CORE_ERROR => array(null, LogLevel::CRITICAL),
);
private $loggers = [
E_DEPRECATED => [null, LogLevel::INFO],
E_USER_DEPRECATED => [null, LogLevel::INFO],
E_NOTICE => [null, LogLevel::WARNING],
E_USER_NOTICE => [null, LogLevel::WARNING],
E_STRICT => [null, LogLevel::WARNING],
E_WARNING => [null, LogLevel::WARNING],
E_USER_WARNING => [null, LogLevel::WARNING],
E_COMPILE_WARNING => [null, LogLevel::WARNING],
E_CORE_WARNING => [null, LogLevel::WARNING],
E_USER_ERROR => [null, LogLevel::CRITICAL],
E_RECOVERABLE_ERROR => [null, LogLevel::CRITICAL],
E_COMPILE_ERROR => [null, LogLevel::CRITICAL],
E_PARSE => [null, LogLevel::CRITICAL],
E_ERROR => [null, LogLevel::CRITICAL],
E_CORE_ERROR => [null, LogLevel::CRITICAL],
];
private $thrownErrors = 0x1FFF; // E_ALL - E_DEPRECATED - E_USER_DEPRECATED
private $scopedErrors = 0x1FFF; // E_ALL - E_DEPRECATED - E_USER_DEPRECATED
@@ -97,7 +98,7 @@ class ErrorHandler
private static $reservedMemory;
private static $toStringException = null;
private static $silencedErrorCache = array();
private static $silencedErrorCache = [];
private static $silencedErrorCount = 0;
private static $exitCode = 0;
@@ -120,29 +121,29 @@ class ErrorHandler
$handler = new static();
}
if (null === $prev = set_error_handler(array($handler, 'handleError'))) {
if (null === $prev = set_error_handler([$handler, 'handleError'])) {
restore_error_handler();
// Specifying the error types earlier would expose us to https://bugs.php.net/63206
set_error_handler(array($handler, 'handleError'), $handler->thrownErrors | $handler->loggedErrors);
set_error_handler([$handler, 'handleError'], $handler->thrownErrors | $handler->loggedErrors);
$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) {
restore_error_handler();
$handlerIsRegistered = is_array($prev) && $handler === $prev[0];
$handlerIsRegistered = \is_array($prev) && $handler === $prev[0];
} else {
$handlerIsRegistered = true;
}
if (is_array($prev = set_exception_handler(array($handler, 'handleException'))) && $prev[0] instanceof self) {
if (\is_array($prev = set_exception_handler([$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'));
set_exception_handler([$handler, 'handleException']);
$p = $prev[0]->setExceptionHandler(null);
$handler->setExceptionHandler($p);
$prev[0]->setExceptionHandler($p);
@@ -175,12 +176,12 @@ class ErrorHandler
*/
public function setDefaultLogger(LoggerInterface $logger, $levels = E_ALL, $replace = false)
{
$loggers = array();
$loggers = [];
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);
$loggers[$type] = [$logger, $logLevel];
}
}
} else {
@@ -211,15 +212,15 @@ class ErrorHandler
{
$prevLogged = $this->loggedErrors;
$prev = $this->loggers;
$flush = array();
$flush = [];
foreach ($loggers as $type => $log) {
if (!isset($prev[$type])) {
throw new \InvalidArgumentException('Unknown error type: '.$type);
}
if (!is_array($log)) {
$log = array($log);
} elseif (!array_key_exists(0, $log)) {
if (!\is_array($log)) {
$log = [$log];
} elseif (!\array_key_exists(0, $log)) {
throw new \InvalidArgumentException('No logger provided');
}
if (null === $log[0]) {
@@ -350,14 +351,14 @@ 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();
if ($this->isRoot) {
set_error_handler(array($this, 'handleError'), $this->thrownErrors | $this->loggedErrors);
set_error_handler([$this, 'handleError'], $this->thrownErrors | $this->loggedErrors);
} else {
set_error_handler(array($this, 'handleError'));
set_error_handler([$this, 'handleError']);
}
}
}
@@ -393,10 +394,10 @@ class ErrorHandler
}
$scope = $this->scopedErrors & $type;
if (4 < $numArgs = func_num_args()) {
$context = $scope ? (func_get_arg(4) ?: array()) : array();
if (4 < $numArgs = \func_num_args()) {
$context = $scope ? (func_get_arg(4) ?: []) : [];
} else {
$context = array();
$context = [];
}
if (isset($context['GLOBALS']) && $scope) {
@@ -405,26 +406,30 @@ class ErrorHandler
$context = $e;
}
$logMessage = $this->levels[$type].': '.$message;
if (false !== strpos($message, "class@anonymous\0")) {
$logMessage = $this->levels[$type].': '.(new FlattenException())->setMessage($message)->getMessage();
} else {
$logMessage = $this->levels[$type].': '.$message;
}
if (null !== self::$toStringException) {
$errorAsException = self::$toStringException;
self::$toStringException = null;
} elseif (!$throw && !($type & $level)) {
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);
$lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5), $type, $file, $line, false) : [];
$errorAsException = new SilencedErrorContext($type, $file, $line, isset($lightTrace[1]) ? [$lightTrace[0]] : $lightTrace);
} elseif (isset(self::$silencedErrorCache[$id][$message])) {
$lightTrace = null;
$errorAsException = self::$silencedErrorCache[$id][$message];
++$errorAsException->count;
} else {
$lightTrace = array();
$lightTrace = [];
$errorAsException = null;
}
if (100 < ++self::$silencedErrorCount) {
self::$silencedErrorCache = $lightTrace = array();
self::$silencedErrorCache = $lightTrace = [];
self::$silencedErrorCount = 1;
}
if ($errorAsException) {
@@ -436,14 +441,13 @@ class ErrorHandler
} else {
$errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line);
// Clean the trace by removing function arguments and the first frames added by the error handler itself.
if ($throw || $this->tracedErrors & $type) {
$backtrace = $errorAsException->getTrace();
$lightTrace = $this->cleanTrace($backtrace, $type, $file, $line, $throw);
$this->traceReflector->setValue($errorAsException, $lightTrace);
} else {
$this->traceReflector->setValue($errorAsException, array());
$backtrace = array();
$this->traceReflector->setValue($errorAsException, []);
$backtrace = [];
}
}
@@ -486,12 +490,21 @@ class ErrorHandler
if ($this->isRecursive) {
$log = 0;
} else {
if (!\defined('HHVM_VERSION')) {
$currentErrorHandler = set_error_handler('var_dump');
restore_error_handler();
}
try {
$this->isRecursive = true;
$level = ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG;
$this->loggers[$type][0]->log($level, $logMessage, $errorAsException ? array('exception' => $errorAsException) : array());
$this->loggers[$type][0]->log($level, $logMessage, $errorAsException ? ['exception' => $errorAsException] : []);
} finally {
$this->isRecursive = false;
if (!\defined('HHVM_VERSION')) {
set_error_handler($currentErrorHandler);
}
}
}
@@ -518,26 +531,29 @@ class ErrorHandler
$handlerException = null;
if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
if (false !== strpos($message = $exception->getMessage(), "class@anonymous\0")) {
$message = (new FlattenException())->setMessage($message)->getMessage();
}
if ($exception instanceof FatalErrorException) {
if ($exception instanceof FatalThrowableError) {
$error = array(
$error = [
'type' => $type,
'message' => $message = $exception->getMessage(),
'message' => $message,
'file' => $exception->getFile(),
'line' => $exception->getLine(),
);
];
} else {
$message = 'Fatal '.$exception->getMessage();
$message = 'Fatal '.$message;
}
} elseif ($exception instanceof \ErrorException) {
$message = 'Uncaught '.$exception->getMessage();
$message = 'Uncaught '.$message;
} else {
$message = 'Uncaught Exception: '.$exception->getMessage();
$message = 'Uncaught Exception: '.$message;
}
}
if ($this->loggedErrors & $type) {
try {
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, array('exception' => $exception));
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, ['exception' => $exception]);
} catch (\Throwable $handlerException) {
}
}
@@ -553,7 +569,7 @@ class ErrorHandler
$this->exceptionHandler = null;
try {
if (null !== $exceptionHandler) {
return \call_user_func($exceptionHandler, $exception);
return $exceptionHandler($exception);
}
$handlerException = $handlerException ?: $exception;
} catch (\Throwable $handlerException) {
@@ -579,11 +595,11 @@ class ErrorHandler
}
$handler = self::$reservedMemory = null;
$handlers = array();
$handlers = [];
$previousHandler = null;
$sameHandlerLimit = 10;
while (!is_array($handler) || !$handler[0] instanceof self) {
while (!\is_array($handler) || !$handler[0] instanceof self) {
$handler = set_exception_handler('var_dump');
restore_exception_handler();
@@ -610,7 +626,7 @@ class ErrorHandler
$handler[0]->setExceptionHandler($h);
}
$handler = $handler[0];
$handlers = array();
$handlers = [];
if ($exit = null === $error) {
$error = error_get_last();
@@ -654,23 +670,33 @@ class ErrorHandler
*/
protected function getFatalErrorHandlers()
{
return array(
return [
new UndefinedFunctionFatalErrorHandler(),
new UndefinedMethodFatalErrorHandler(),
new ClassNotFoundFatalErrorHandler(),
);
];
}
/**
* Cleans the trace by removing function arguments and the frames added by the error handler and DebugClassLoader.
*/
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);
$lightTrace = \array_slice($lightTrace, 1 + $i);
break;
}
}
if (class_exists(DebugClassLoader::class, false)) {
for ($i = \count($lightTrace) - 2; 0 < $i; --$i) {
if (DebugClassLoader::class === ($lightTrace[$i]['class'] ?? null)) {
array_splice($lightTrace, --$i, 2);
}
}
}
if (!($throw || $this->scopedErrors & $type)) {
for ($i = 0; isset($lightTrace[$i]); ++$i) {
unset($lightTrace[$i]['args'], $lightTrace[$i]['object']);

View File

@@ -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);
@@ -61,7 +61,7 @@ class FatalErrorException extends \ErrorException
unset($frame);
$trace = array_reverse($trace);
} else {
$trace = array();
$trace = [];
}
$this->setTrace($trace);

View File

@@ -33,12 +33,12 @@ class FlattenException
private $file;
private $line;
public static function create(\Exception $exception, $statusCode = null, array $headers = array())
public static function create(\Exception $exception, $statusCode = null, array $headers = [])
{
return static::createFromThrowable($exception, $statusCode, $headers);
}
public static function createFromThrowable(\Throwable $exception, ?int $statusCode = null, array $headers = array()): self
public static function createFromThrowable(\Throwable $exception, ?int $statusCode = null, array $headers = []): self
{
$e = new static();
$e->setMessage($exception->getMessage());
@@ -73,13 +73,13 @@ class FlattenException
public function toArray()
{
$exceptions = array();
foreach (array_merge(array($this), $this->getAllPrevious()) as $exception) {
$exceptions[] = array(
$exceptions = [];
foreach (array_merge([$this], $this->getAllPrevious()) as $exception) {
$exceptions[] = [
'message' => $exception->getMessage(),
'class' => $exception->getClass(),
'trace' => $exception->getTrace(),
);
];
}
return $exceptions;
@@ -90,9 +90,14 @@ class FlattenException
return $this->statusCode;
}
/**
* @return $this
*/
public function setStatusCode($code)
{
$this->statusCode = $code;
return $this;
}
public function getHeaders()
@@ -100,9 +105,14 @@ class FlattenException
return $this->headers;
}
/**
* @return $this
*/
public function setHeaders(array $headers)
{
$this->headers = $headers;
return $this;
}
public function getClass()
@@ -110,9 +120,14 @@ class FlattenException
return $this->class;
}
/**
* @return $this
*/
public function setClass($class)
{
$this->class = $class;
$this->class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
return $this;
}
public function getFile()
@@ -120,9 +135,14 @@ class FlattenException
return $this->file;
}
/**
* @return $this
*/
public function setFile($file)
{
$this->file = $file;
return $this;
}
public function getLine()
@@ -130,9 +150,14 @@ class FlattenException
return $this->line;
}
/**
* @return $this
*/
public function setLine($line)
{
$this->line = $line;
return $this;
}
public function getMessage()
@@ -140,9 +165,20 @@ class FlattenException
return $this->message;
}
/**
* @return $this
*/
public function setMessage($message)
{
if (false !== strpos($message, "class@anonymous\0")) {
$message = preg_replace_callback('/class@anonymous\x00.*?\.php0x?[0-9a-fA-F]++/', function ($m) {
return \class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
}, $message);
}
$this->message = $message;
return $this;
}
public function getCode()
@@ -150,9 +186,14 @@ class FlattenException
return $this->code;
}
/**
* @return $this
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
public function getPrevious()
@@ -160,14 +201,19 @@ class FlattenException
return $this->previous;
}
/**
* @return $this
*/
public function setPrevious(self $previous)
{
$this->previous = $previous;
return $this;
}
public function getAllPrevious()
{
$exceptions = array();
$exceptions = [];
$e = $this;
while ($e = $e->getPrevious()) {
$exceptions[] = $e;
@@ -186,20 +232,23 @@ class FlattenException
*/
public function setTraceFromException(\Exception $exception)
{
@trigger_error(sprintf('"%s" is deprecated since Symfony 4.1, use "setTraceFromThrowable()" instead.', __METHOD__), E_USER_DEPRECATED);
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use "setTraceFromThrowable()" instead.', __METHOD__), E_USER_DEPRECATED);
$this->setTraceFromThrowable($exception);
}
public function setTraceFromThrowable(\Throwable $throwable): void
public function setTraceFromThrowable(\Throwable $throwable)
{
$this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine());
return $this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine());
}
/**
* @return $this
*/
public function setTrace($trace, $file, $line)
{
$this->trace = array();
$this->trace[] = array(
$this->trace = [];
$this->trace[] = [
'namespace' => '',
'short_class' => '',
'class' => '',
@@ -207,8 +256,8 @@ class FlattenException
'function' => '',
'file' => $file,
'line' => $line,
'args' => array(),
);
'args' => [],
];
foreach ($trace as $entry) {
$class = '';
$namespace = '';
@@ -218,7 +267,7 @@ class FlattenException
$namespace = implode('\\', $parts);
}
$this->trace[] = array(
$this->trace[] = [
'namespace' => $namespace,
'short_class' => $class,
'class' => isset($entry['class']) ? $entry['class'] : '',
@@ -226,41 +275,43 @@ class FlattenException
'function' => isset($entry['function']) ? $entry['function'] : null,
'file' => isset($entry['file']) ? $entry['file'] : null,
'line' => isset($entry['line']) ? $entry['line'] : null,
'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : array(),
);
'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : [],
];
}
return $this;
}
private function flattenArgs($args, $level = 0, &$count = 0)
{
$result = array();
$result = [];
foreach ($args as $key => $value) {
if (++$count > 1e4) {
return array('array', '*SKIPPED over 10000 entries*');
return ['array', '*SKIPPED over 10000 entries*'];
}
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)) {
$result[$key] = ['incomplete-object', $this->getClassNameFromIncomplete($value)];
} elseif (\is_object($value)) {
$result[$key] = ['object', \get_class($value)];
} elseif (\is_array($value)) {
if ($level > 10) {
$result[$key] = array('array', '*DEEP NESTED ARRAY*');
$result[$key] = ['array', '*DEEP NESTED ARRAY*'];
} else {
$result[$key] = array('array', $this->flattenArgs($value, $level + 1, $count));
$result[$key] = ['array', $this->flattenArgs($value, $level + 1, $count)];
}
} elseif (null === $value) {
$result[$key] = array('null', null);
} elseif (is_bool($value)) {
$result[$key] = array('boolean', $value);
} elseif (is_int($value)) {
$result[$key] = array('integer', $value);
} elseif (is_float($value)) {
$result[$key] = array('float', $value);
} elseif (is_resource($value)) {
$result[$key] = array('resource', get_resource_type($value));
$result[$key] = ['null', null];
} elseif (\is_bool($value)) {
$result[$key] = ['boolean', $value];
} elseif (\is_int($value)) {
$result[$key] = ['integer', $value];
} elseif (\is_float($value)) {
$result[$key] = ['float', $value];
} elseif (\is_resource($value)) {
$result[$key] = ['resource', get_resource_type($value)];
} else {
$result[$key] = array('string', (string) $value);
$result[$key] = ['string', (string) $value];
}
}

View File

@@ -25,7 +25,7 @@ class SilencedErrorContext implements \JsonSerializable
private $line;
private $trace;
public function __construct(int $severity, string $file, int $line, array $trace = array(), int $count = 1)
public function __construct(int $severity, string $file, int $line, array $trace = [], int $count = 1)
{
$this->severity = $severity;
$this->file = $file;
@@ -56,12 +56,12 @@ class SilencedErrorContext implements \JsonSerializable
public function JsonSerialize()
{
return array(
return [
'severity' => $this->severity,
'file' => $this->file,
'line' => $this->line,
'trace' => $this->trace,
'count' => $this->count,
);
];
}
}

View File

@@ -56,10 +56,10 @@ class ExceptionHandler
{
$handler = new static($debug, $charset, $fileLinkFormat);
$prev = set_exception_handler(array($handler, 'handle'));
if (is_array($prev) && $prev[0] instanceof ErrorHandler) {
$prev = set_exception_handler([$handler, 'handle']);
if (\is_array($prev) && $prev[0] instanceof ErrorHandler) {
restore_exception_handler();
$prev[0]->setExceptionHandler(array($handler, 'handle'));
$prev[0]->setExceptionHandler([$handler, 'handle']);
}
return $handler;
@@ -142,7 +142,7 @@ class ExceptionHandler
$this->caughtBuffer = null;
try {
call_user_func($this->handler, $exception);
($this->handler)($exception);
$this->caughtLength = $caughtLength;
} catch (\Exception $e) {
if (!$caughtLength) {
@@ -208,48 +208,55 @@ class ExceptionHandler
$title = 'Whoops, looks like something went wrong.';
}
$content = '';
if ($this->debug) {
try {
$count = count($exception->getAllPrevious());
$total = $count + 1;
foreach ($exception->toArray() as $position => $e) {
$ind = $count - $position + 1;
$class = $this->formatClass($e['class']);
$message = nl2br($this->escapeHtml($e['message']));
$content .= sprintf(<<<'EOF'
<div class="trace trace-as-html">
<table class="trace-details">
<thead class="trace-head"><tr><th>
<h3 class="trace-class">
<span class="text-muted">(%d/%d)</span>
<span class="exception_title">%s</span>
</h3>
<p class="break-long-words trace-message">%s</p>
</th></tr></thead>
<tbody>
EOF
, $ind, $total, $class, $message);
foreach ($e['trace'] as $trace) {
$content .= '<tr><td>';
if ($trace['function']) {
$content .= sprintf('at <span class="trace-class">%s</span><span class="trace-type">%s</span><span class="trace-method">%s</span>(<span class="trace-arguments">%s</span>)', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
}
if (isset($trace['file']) && isset($trace['line'])) {
$content .= $this->formatPath($trace['file'], $trace['line']);
}
$content .= "</td></tr>\n";
}
if (!$this->debug) {
return <<<EOF
<div class="container">
<h1>$title</h1>
</div>
EOF;
}
$content .= "</tbody>\n</table>\n</div>\n";
}
} catch (\Exception $e) {
// something nasty happened and we cannot throw an exception anymore
if ($this->debug) {
$title = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $this->escapeHtml($e->getMessage()));
} else {
$title = 'Whoops, looks like something went wrong.';
$content = '';
try {
$count = \count($exception->getAllPrevious());
$total = $count + 1;
foreach ($exception->toArray() as $position => $e) {
$ind = $count - $position + 1;
$class = $this->formatClass($e['class']);
$message = nl2br($this->escapeHtml($e['message']));
$content .= sprintf(<<<'EOF'
<div class="trace trace-as-html">
<table class="trace-details">
<thead class="trace-head"><tr><th>
<h3 class="trace-class">
<span class="text-muted">(%d/%d)</span>
<span class="exception_title">%s</span>
</h3>
<p class="break-long-words trace-message">%s</p>
</th></tr></thead>
<tbody>
EOF
, $ind, $total, $class, $message);
foreach ($e['trace'] as $trace) {
$content .= '<tr><td>';
if ($trace['function']) {
$content .= sprintf('at <span class="trace-class">%s</span><span class="trace-type">%s</span><span class="trace-method">%s</span>(<span class="trace-arguments">%s</span>)', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
}
if (isset($trace['file']) && isset($trace['line'])) {
$content .= $this->formatPath($trace['file'], $trace['line']);
}
$content .= "</td></tr>\n";
}
$content .= "</tbody>\n</table>\n</div>\n";
}
} catch (\Exception $e) {
// something nasty happened and we cannot throw an exception anymore
if ($this->debug) {
$e = FlattenException::create($e);
$title = sprintf('Exception thrown when handling an exception (%s: %s)', $e->getClass(), $this->escapeHtml($e->getMessage()));
} else {
$title = 'Whoops, looks like something went wrong.';
}
}
@@ -278,6 +285,14 @@ EOF;
*/
public function getStylesheet(FlattenException $exception)
{
if (!$this->debug) {
return <<<'EOF'
body { background-color: #fff; color: #222; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; }
.container { margin: 30px; max-width: 600px; }
h1 { color: #dc3545; font-size: 24px; }
EOF;
}
return <<<'EOF'
body { background-color: #F9F9F9; color: #222; font: 14px/1.4 Helvetica, Arial, sans-serif; margin: 0; padding-bottom: 45px; }
@@ -362,17 +377,17 @@ EOF;
}
if (\is_string($fmt)) {
$i = strpos($f = $fmt, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: strlen($f);
$fmt = array(substr($f, 0, $i)) + preg_split('/&([^>]++)>/', substr($f, $i), -1, PREG_SPLIT_DELIM_CAPTURE);
$i = strpos($f = $fmt, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f);
$fmt = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, PREG_SPLIT_DELIM_CAPTURE);
for ($i = 1; isset($fmt[$i]); ++$i) {
if (0 === strpos($path, $k = $fmt[$i++])) {
$path = substr_replace($path, $fmt[$i], 0, strlen($k));
$path = substr_replace($path, $fmt[$i], 0, \strlen($k));
break;
}
}
$link = strtr($fmt[0], array('%f' => $path, '%l' => $line));
$link = strtr($fmt[0], ['%f' => $path, '%l' => $line]);
} else {
$link = $fmt->format($path, $line);
}
@@ -389,12 +404,12 @@ EOF;
*/
private function formatArgs(array $args)
{
$result = array();
$result = [];
foreach ($args as $key => $item) {
if ('object' === $item[0]) {
$formattedValue = sprintf('<em>object</em>(%s)', $this->formatClass($item[1]));
} elseif ('array' === $item[0]) {
$formattedValue = sprintf('<em>array</em>(%s)', is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
$formattedValue = sprintf('<em>array</em>(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
} elseif ('null' === $item[0]) {
$formattedValue = '<em>null</em>';
} elseif ('boolean' === $item[0]) {
@@ -405,7 +420,7 @@ EOF;
$formattedValue = str_replace("\n", '', $this->escapeHtml(var_export($item[1], true)));
}
$result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escapeHtml($key), $formattedValue);
$result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escapeHtml($key), $formattedValue);
}
return implode(', ', $result);

View File

@@ -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;
}
@@ -40,9 +40,9 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
return;
}
foreach (array('class', 'interface', 'trait') as $typeName) {
foreach (['class', 'interface', 'trait'] as $typeName) {
$prefix = ucfirst($typeName).' \'';
$prefixLen = strlen($prefix);
$prefixLen = \strlen($prefix);
if (0 !== strpos($error['message'], $prefix)) {
continue;
}
@@ -85,22 +85,22 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
*/
private function getClassCandidates(string $class): array
{
if (!is_array($functions = spl_autoload_functions())) {
return array();
if (!\is_array($functions = spl_autoload_functions())) {
return [];
}
// find Symfony and Composer autoloaders
$classes = array();
$classes = [];
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;
}
}
@@ -126,11 +126,11 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
private function findClassInPath(string $path, string $class, string $prefix): array
{
if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
return array();
if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
return [];
}
$classes = array();
$classes = [];
$filename = $class.'.php';
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
if ($filename == $file->getFileName() && $class = $this->convertFileToClass($path, $file->getPathName(), $prefix)) {
@@ -143,9 +143,9 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
private function convertFileToClass(string $path, string $file, string $prefix): ?string
{
$candidates = array(
$candidates = [
// namespaced class
$namespacedClass = str_replace(array($path.DIRECTORY_SEPARATOR, '.php', '/'), array('', '', '\\'), $file),
$namespacedClass = str_replace([$path.\DIRECTORY_SEPARATOR, '.php', '/'], ['', '', '\\'], $file),
// namespaced class (with target dir)
$prefix.$namespacedClass,
// namespaced class (with target dir and separator)
@@ -156,7 +156,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
str_replace('\\', '_', $prefix.$namespacedClass),
// PEAR class (with target dir and separator)
str_replace('\\', '_', $prefix.'\\'.$namespacedClass),
);
];
if ($prefix) {
$candidates = array_filter($candidates, function ($candidate) use ($prefix) { return 0 === strpos($candidate, $prefix); });

View File

@@ -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;
}
@@ -53,7 +53,7 @@ class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface
$message = sprintf('Attempted to call function "%s" from the global namespace.', $functionName);
}
$candidates = array();
$candidates = [];
foreach (get_defined_functions() as $type => $definedFunctionNames) {
foreach ($definedFunctionNames as $definedFunctionName) {
if (false !== $namespaceSeparatorIndex = strrpos($definedFunctionName, '\\')) {

View File

@@ -41,10 +41,10 @@ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
return new UndefinedMethodException($message, $exception);
}
$candidates = array();
$candidates = [];
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;
}
}

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2018 Fabien Potencier
Copyright (c) 2004-2019 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

View File

@@ -27,14 +27,14 @@ class DebugClassLoaderTest extends TestCase
{
$this->errorReporting = error_reporting(E_ALL);
$this->loader = new ClassLoader();
spl_autoload_register(array($this->loader, 'loadClass'), true, true);
spl_autoload_register([$this->loader, 'loadClass'], true, true);
DebugClassLoader::enable();
}
protected function tearDown()
{
DebugClassLoader::disable();
spl_autoload_unregister(array($this->loader, 'loadClass'));
spl_autoload_unregister([$this->loader, 'loadClass']);
error_reporting($this->errorReporting);
}
@@ -44,7 +44,7 @@ class DebugClassLoaderTest extends TestCase
$functions = spl_autoload_functions();
foreach ($functions as $function) {
if (is_array($function) && $function[0] instanceof DebugClassLoader) {
if (\is_array($function) && $function[0] instanceof DebugClassLoader) {
$reflClass = new \ReflectionClass($function[0]);
$reflProp = $reflClass->getProperty('classLoader');
$reflProp->setAccessible(true);
@@ -136,20 +136,20 @@ class DebugClassLoaderTest extends TestCase
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$xError = array(
$xError = [
'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.',
);
];
$this->assertSame($xError, $lastError);
}
public function provideDeprecatedSuper()
{
return array(
array('DeprecatedInterfaceClass', 'DeprecatedInterface', 'implements'),
array('DeprecatedParentClass', 'DeprecatedClass', 'extends'),
);
return [
['DeprecatedInterfaceClass', 'DeprecatedInterface', 'implements'],
['DeprecatedParentClass', 'DeprecatedClass', 'extends'],
];
}
public function testInterfaceExtendsDeprecatedInterface()
@@ -166,10 +166,10 @@ class DebugClassLoaderTest extends TestCase
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$xError = array(
$xError = [
'type' => E_USER_NOTICE,
'message' => '',
);
];
$this->assertSame($xError, $lastError);
}
@@ -188,56 +188,60 @@ class DebugClassLoaderTest extends TestCase
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$xError = array(
$xError = [
'type' => E_USER_NOTICE,
'message' => '',
);
];
$this->assertSame($xError, $lastError);
}
public function testExtendedFinalClass()
{
set_error_handler(function () { return false; });
$e = error_reporting(0);
trigger_error('', E_USER_NOTICE);
$deprecations = [];
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
$e = error_reporting(E_USER_DEPRECATED);
class_exists('Test\\'.__NAMESPACE__.'\\ExtendsFinalClass', true);
require __DIR__.'/Fixtures/FinalClasses.php';
$i = 1;
while (class_exists($finalClass = __NAMESPACE__.'\\Fixtures\\FinalClass'.$i++, false)) {
spl_autoload_call($finalClass);
class_exists('Test\\'.__NAMESPACE__.'\\Extends'.substr($finalClass, strrpos($finalClass, '\\') + 1), 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. 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);
$this->assertSame([
'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass1" 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\ExtendsFinalClass1".',
'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass2" class is considered final. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass2".',
'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass3" class is considered final comment with @@@ and ***. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass3".',
'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass4" class is considered final. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass4".',
'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass5" class is considered final multiline comment. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass5".',
'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass6" class is considered final. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass6".',
'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass7" class is considered final another multiline comment... It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass7".',
'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass8" class is considered final. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass8".',
], $deprecations);
}
public function testExtendedFinalMethod()
{
set_error_handler(function () { return false; });
$e = error_reporting(0);
trigger_error('', E_USER_NOTICE);
$deprecations = [];
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();
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$xError = [
'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" 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".',
'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".',
];
$xError = array(
'type' => E_USER_DEPRECATED,
'message' => 'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" 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, $lastError);
$this->assertSame($xError, $deprecations);
}
public function testExtendedDeprecatedMethodDoesntTriggerAnyNotice()
@@ -254,12 +258,12 @@ class DebugClassLoaderTest extends TestCase
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$this->assertSame(array('type' => E_USER_NOTICE, 'message' => ''), $lastError);
$this->assertSame(['type' => E_USER_NOTICE, 'message' => ''], $lastError);
}
public function testInternalsUse()
{
$deprecations = array();
$deprecations = [];
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
$e = error_reporting(E_USER_DEPRECATED);
@@ -268,12 +272,49 @@ class DebugClassLoaderTest extends TestCase
error_reporting($e);
restore_error_handler();
$this->assertSame($deprecations, array(
'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass" class is considered internal. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternalsParent".',
$this->assertSame($deprecations, [
'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. 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\InternalTrait2::internalMethod()" method is considered internal. It may change without further notice. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".',
));
'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass::internalMethod()" method is considered internal. It may change without further notice. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".',
]);
}
public function testExtendedMethodDefinesNewParameters()
{
$deprecations = [];
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
$e = error_reporting(E_USER_DEPRECATED);
class_exists(__NAMESPACE__.'\\Fixtures\SubClassWithAnnotatedParameters', true);
error_reporting($e);
restore_error_handler();
$this->assertSame([
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::quzMethod()" method will require a new "Quz $quz" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\ClassWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::whereAmI()" method will require a new "bool $matrix" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::isSymfony()" method will require a new "true $yes" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\ClassWithAnnotatedParameters", not defining it is deprecated.',
], $deprecations);
}
public function testUseTraitWithInternalMethod()
{
$deprecations = [];
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([], $deprecations);
}
public function testEvaluatedCode()
{
$this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\DefinitionInEvaluatedCode', true));
}
}
@@ -285,12 +326,12 @@ class ClassLoader
public function getClassMap()
{
return array(__NAMESPACE__.'\Fixtures\NotPSR0bis' => __DIR__.'/Fixtures/notPsr0Bis.php');
return [__NAMESPACE__.'\Fixtures\NotPSR0bis' => __DIR__.'/Fixtures/notPsr0Bis.php'];
}
public function findFile($class)
{
$fixtureDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR;
$fixtureDir = __DIR__.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR;
if (__NAMESPACE__.'\TestingUnsilencing' === $class) {
eval('-- parse error --');
@@ -299,7 +340,7 @@ class ClassLoader
} elseif (__NAMESPACE__.'\TestingCaseMismatch' === $class) {
eval('namespace '.__NAMESPACE__.'; class TestingCaseMisMatch {}');
} elseif (__NAMESPACE__.'\Fixtures\Psr4CaseMismatch' === $class) {
return $fixtureDir.'psr4'.DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php';
return $fixtureDir.'psr4'.\DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php';
} elseif (__NAMESPACE__.'\Fixtures\NotPSR0' === $class) {
return $fixtureDir.'reallyNotPsr0.php';
} elseif (__NAMESPACE__.'\Fixtures\NotPSR0bis' === $class) {
@@ -314,8 +355,9 @@ 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 (0 === strpos($class, 'Test\\'.__NAMESPACE__.'\ExtendsFinalClass')) {
$classShortName = substr($class, strrpos($class, '\\') + 1);
eval('namespace Test\\'.__NAMESPACE__.'; class '.$classShortName.' extends \\'.__NAMESPACE__.'\Fixtures\\'.substr($classShortName, 7).' {}');
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsAnnotatedClass' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsAnnotatedClass extends \\'.__NAMESPACE__.'\Fixtures\AnnotatedClass {
public function deprecatedMethod() { }
@@ -328,6 +370,8 @@ class ClassLoader
}');
} 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; }');
}
}
}

View File

@@ -13,9 +13,12 @@ namespace Symfony\Component\Debug\Tests;
use PHPUnit\Framework\TestCase;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;
use Symfony\Component\Debug\BufferingLogger;
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\Exception\SilencedErrorContext;
use Symfony\Component\Debug\Tests\Fixtures\ErrorHandlerThatUsesThePreviousOne;
use Symfony\Component\Debug\Tests\Fixtures\LoggerThatSetAnErrorHandler;
/**
* ErrorHandlerTest.
@@ -38,13 +41,13 @@ class ErrorHandlerTest extends TestCase
$this->assertSame($handler, ErrorHandler::register($newHandler, false));
$h = set_error_handler('var_dump');
restore_error_handler();
$this->assertSame(array($handler, 'handleError'), $h);
$this->assertSame([$handler, 'handleError'], $h);
try {
$this->assertSame($newHandler, ErrorHandler::register($newHandler, true));
$h = set_error_handler('var_dump');
restore_error_handler();
$this->assertSame(array($newHandler, 'handleError'), $h);
$this->assertSame([$newHandler, 'handleError'], $h);
} catch (\Exception $e) {
}
@@ -74,12 +77,12 @@ class ErrorHandlerTest extends TestCase
try {
@trigger_error('Hello', E_USER_WARNING);
$expected = array(
$expected = [
'type' => E_USER_WARNING,
'message' => 'Hello',
'file' => __FILE__,
'line' => __LINE__ - 5,
);
];
$this->assertSame($expected, error_get_last());
} catch (\Exception $e) {
restore_error_handler();
@@ -145,26 +148,26 @@ class ErrorHandlerTest extends TestCase
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$handler->setDefaultLogger($logger, E_NOTICE);
$handler->setDefaultLogger($logger, array(E_USER_NOTICE => LogLevel::CRITICAL));
$handler->setDefaultLogger($logger, [E_USER_NOTICE => LogLevel::CRITICAL]);
$loggers = array(
E_DEPRECATED => array(null, LogLevel::INFO),
E_USER_DEPRECATED => array(null, LogLevel::INFO),
E_NOTICE => array($logger, LogLevel::WARNING),
E_USER_NOTICE => array($logger, LogLevel::CRITICAL),
E_STRICT => array(null, LogLevel::WARNING),
E_WARNING => array(null, LogLevel::WARNING),
E_USER_WARNING => array(null, LogLevel::WARNING),
E_COMPILE_WARNING => array(null, LogLevel::WARNING),
E_CORE_WARNING => array(null, LogLevel::WARNING),
E_USER_ERROR => array(null, LogLevel::CRITICAL),
E_RECOVERABLE_ERROR => array(null, LogLevel::CRITICAL),
E_COMPILE_ERROR => array(null, LogLevel::CRITICAL),
E_PARSE => array(null, LogLevel::CRITICAL),
E_ERROR => array(null, LogLevel::CRITICAL),
E_CORE_ERROR => array(null, LogLevel::CRITICAL),
);
$this->assertSame($loggers, $handler->setLoggers(array()));
$loggers = [
E_DEPRECATED => [null, LogLevel::INFO],
E_USER_DEPRECATED => [null, LogLevel::INFO],
E_NOTICE => [$logger, LogLevel::WARNING],
E_USER_NOTICE => [$logger, LogLevel::CRITICAL],
E_STRICT => [null, LogLevel::WARNING],
E_WARNING => [null, LogLevel::WARNING],
E_USER_WARNING => [null, LogLevel::WARNING],
E_COMPILE_WARNING => [null, LogLevel::WARNING],
E_CORE_WARNING => [null, LogLevel::WARNING],
E_USER_ERROR => [null, LogLevel::CRITICAL],
E_RECOVERABLE_ERROR => [null, LogLevel::CRITICAL],
E_COMPILE_ERROR => [null, LogLevel::CRITICAL],
E_PARSE => [null, LogLevel::CRITICAL],
E_ERROR => [null, LogLevel::CRITICAL],
E_CORE_ERROR => [null, LogLevel::CRITICAL],
];
$this->assertSame($loggers, $handler->setLoggers([]));
} finally {
restore_error_handler();
restore_exception_handler();
@@ -176,14 +179,14 @@ class ErrorHandlerTest extends TestCase
try {
$handler = ErrorHandler::register();
$handler->throwAt(0, true);
$this->assertFalse($handler->handleError(0, 'foo', 'foo.php', 12, array()));
$this->assertFalse($handler->handleError(0, 'foo', 'foo.php', 12, []));
restore_error_handler();
restore_exception_handler();
$handler = ErrorHandler::register();
$handler->throwAt(3, true);
$this->assertFalse($handler->handleError(4, 'foo', 'foo.php', 12, array()));
$this->assertFalse($handler->handleError(4, 'foo', 'foo.php', 12, []));
restore_error_handler();
restore_exception_handler();
@@ -191,7 +194,7 @@ class ErrorHandlerTest extends TestCase
$handler = ErrorHandler::register();
$handler->throwAt(3, true);
try {
$handler->handleError(4, 'foo', 'foo.php', 12, array());
$handler->handleError(4, 'foo', 'foo.php', 12, []);
} catch (\ErrorException $e) {
$this->assertSame('Parse Error: foo', $e->getMessage());
$this->assertSame(4, $e->getSeverity());
@@ -204,14 +207,14 @@ class ErrorHandlerTest extends TestCase
$handler = ErrorHandler::register();
$handler->throwAt(E_USER_DEPRECATED, true);
$this->assertFalse($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, array()));
$this->assertFalse($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, []));
restore_error_handler();
restore_exception_handler();
$handler = ErrorHandler::register();
$handler->throwAt(E_DEPRECATED, true);
$this->assertFalse($handler->handleError(E_DEPRECATED, 'foo', 'foo.php', 12, array()));
$this->assertFalse($handler->handleError(E_DEPRECATED, 'foo', 'foo.php', 12, []));
restore_error_handler();
restore_exception_handler();
@@ -236,7 +239,7 @@ class ErrorHandlerTest extends TestCase
$handler = ErrorHandler::register();
$handler->setDefaultLogger($logger, E_USER_DEPRECATED);
$this->assertTrue($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, array()));
$this->assertTrue($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, []));
restore_error_handler();
restore_exception_handler();
@@ -320,7 +323,9 @@ class ErrorHandlerTest extends TestCase
$handler = new ErrorHandler();
$handler->setDefaultLogger($logger);
@$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, array());
@$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, []);
restore_error_handler();
}
public function testHandleException()
@@ -369,27 +374,27 @@ class ErrorHandlerTest extends TestCase
$bootLogger = new BufferingLogger();
$handler = new ErrorHandler($bootLogger);
$loggers = array(
E_DEPRECATED => array($bootLogger, LogLevel::INFO),
E_USER_DEPRECATED => array($bootLogger, LogLevel::INFO),
E_NOTICE => array($bootLogger, LogLevel::WARNING),
E_USER_NOTICE => array($bootLogger, LogLevel::WARNING),
E_STRICT => array($bootLogger, LogLevel::WARNING),
E_WARNING => array($bootLogger, LogLevel::WARNING),
E_USER_WARNING => array($bootLogger, LogLevel::WARNING),
E_COMPILE_WARNING => array($bootLogger, LogLevel::WARNING),
E_CORE_WARNING => array($bootLogger, LogLevel::WARNING),
E_USER_ERROR => array($bootLogger, LogLevel::CRITICAL),
E_RECOVERABLE_ERROR => array($bootLogger, LogLevel::CRITICAL),
E_COMPILE_ERROR => array($bootLogger, LogLevel::CRITICAL),
E_PARSE => array($bootLogger, LogLevel::CRITICAL),
E_ERROR => array($bootLogger, LogLevel::CRITICAL),
E_CORE_ERROR => array($bootLogger, LogLevel::CRITICAL),
);
$loggers = [
E_DEPRECATED => [$bootLogger, LogLevel::INFO],
E_USER_DEPRECATED => [$bootLogger, LogLevel::INFO],
E_NOTICE => [$bootLogger, LogLevel::WARNING],
E_USER_NOTICE => [$bootLogger, LogLevel::WARNING],
E_STRICT => [$bootLogger, LogLevel::WARNING],
E_WARNING => [$bootLogger, LogLevel::WARNING],
E_USER_WARNING => [$bootLogger, LogLevel::WARNING],
E_COMPILE_WARNING => [$bootLogger, LogLevel::WARNING],
E_CORE_WARNING => [$bootLogger, LogLevel::WARNING],
E_USER_ERROR => [$bootLogger, LogLevel::CRITICAL],
E_RECOVERABLE_ERROR => [$bootLogger, LogLevel::CRITICAL],
E_COMPILE_ERROR => [$bootLogger, LogLevel::CRITICAL],
E_PARSE => [$bootLogger, LogLevel::CRITICAL],
E_ERROR => [$bootLogger, LogLevel::CRITICAL],
E_CORE_ERROR => [$bootLogger, LogLevel::CRITICAL],
];
$this->assertSame($loggers, $handler->setLoggers(array()));
$this->assertSame($loggers, $handler->setLoggers([]));
$handler->handleError(E_DEPRECATED, 'Foo message', __FILE__, 123, array());
$handler->handleError(E_DEPRECATED, 'Foo message', __FILE__, 123, []);
$logs = $bootLogger->cleanLogs();
@@ -405,14 +410,14 @@ class ErrorHandlerTest extends TestCase
$this->assertSame(123, $exception->getLine());
$this->assertSame(E_DEPRECATED, $exception->getSeverity());
$bootLogger->log(LogLevel::WARNING, 'Foo message', array('exception' => $exception));
$bootLogger->log(LogLevel::WARNING, 'Foo message', ['exception' => $exception]);
$mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$mockLogger->expects($this->once())
->method('log')
->with(LogLevel::WARNING, 'Foo message', array('exception' => $exception));
->with(LogLevel::WARNING, 'Foo message', ['exception' => $exception]);
$handler->setLoggers(array(E_DEPRECATED => array($mockLogger, LogLevel::WARNING)));
$handler->setLoggers([E_DEPRECATED => [$mockLogger, LogLevel::WARNING]]);
}
public function testSettingLoggerWhenExceptionIsBuffered()
@@ -425,7 +430,7 @@ class ErrorHandlerTest extends TestCase
$mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$mockLogger->expects($this->once())
->method('log')
->with(LogLevel::CRITICAL, 'Uncaught Exception: Foo message', array('exception' => $exception));
->with(LogLevel::CRITICAL, 'Uncaught Exception: Foo message', ['exception' => $exception]);
$handler->setExceptionHandler(function () use ($handler, $mockLogger) {
$handler->setDefaultLogger($mockLogger);
@@ -439,12 +444,12 @@ class ErrorHandlerTest extends TestCase
try {
$handler = ErrorHandler::register();
$error = array(
$error = [
'type' => E_PARSE,
'message' => 'foo',
'file' => 'bar',
'line' => 123,
);
];
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
@@ -480,7 +485,7 @@ class ErrorHandlerTest extends TestCase
$handler = new ErrorHandler();
$handler->setExceptionHandler(function () use (&$args) {
$args = func_get_args();
$args = \func_get_args();
});
$handler->handleException($exception);
@@ -501,4 +506,58 @@ class ErrorHandlerTest extends TestCase
$handler->handleException(new \Exception());
}
/**
* @dataProvider errorHandlerWhenLoggingProvider
*/
public function testErrorHandlerWhenLogging($previousHandlerWasDefined, $loggerSetsAnotherHandler, $nextHandlerIsDefined)
{
try {
if ($previousHandlerWasDefined) {
set_error_handler('count');
}
$logger = $loggerSetsAnotherHandler ? new LoggerThatSetAnErrorHandler() : new NullLogger();
$handler = ErrorHandler::register();
$handler->setDefaultLogger($logger);
if ($nextHandlerIsDefined) {
$handler = ErrorHandlerThatUsesThePreviousOne::register();
}
@trigger_error('foo', E_USER_DEPRECATED);
@trigger_error('bar', E_USER_DEPRECATED);
$this->assertSame([$handler, 'handleError'], set_error_handler('var_dump'));
if ($logger instanceof LoggerThatSetAnErrorHandler) {
$this->assertCount(2, $logger->cleanLogs());
}
restore_error_handler();
if ($previousHandlerWasDefined) {
restore_error_handler();
}
if ($nextHandlerIsDefined) {
restore_error_handler();
}
} finally {
restore_error_handler();
restore_exception_handler();
}
}
public function errorHandlerWhenLoggingProvider()
{
foreach ([false, true] as $previousHandlerWasDefined) {
foreach ([false, true] as $loggerSetsAnotherHandler) {
foreach ([false, true] as $nextHandlerIsDefined) {
yield [$previousHandlerWasDefined, $loggerSetsAnotherHandler, $nextHandlerIsDefined];
}
}
}
}
}

View File

@@ -15,19 +15,19 @@ use PHPUnit\Framework\TestCase;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
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\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
@@ -61,7 +61,7 @@ class FlattenExceptionTest extends TestCase
$flattened = FlattenException::create(new ConflictHttpException());
$this->assertEquals('409', $flattened->getStatusCode());
$flattened = FlattenException::create(new MethodNotAllowedHttpException(array('POST')));
$flattened = FlattenException::create(new MethodNotAllowedHttpException(['POST']));
$this->assertEquals('405', $flattened->getStatusCode());
$flattened = FlattenException::create(new AccessDeniedHttpException());
@@ -96,23 +96,23 @@ class FlattenExceptionTest extends TestCase
public function testHeadersForHttpException()
{
$flattened = FlattenException::create(new MethodNotAllowedHttpException(array('POST')));
$this->assertEquals(array('Allow' => 'POST'), $flattened->getHeaders());
$flattened = FlattenException::create(new MethodNotAllowedHttpException(['POST']));
$this->assertEquals(['Allow' => 'POST'], $flattened->getHeaders());
$flattened = FlattenException::create(new UnauthorizedHttpException('Basic realm="My Realm"'));
$this->assertEquals(array('WWW-Authenticate' => 'Basic realm="My Realm"'), $flattened->getHeaders());
$this->assertEquals(['WWW-Authenticate' => 'Basic realm="My Realm"'], $flattened->getHeaders());
$flattened = FlattenException::create(new ServiceUnavailableHttpException('Fri, 31 Dec 1999 23:59:59 GMT'));
$this->assertEquals(array('Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'), $flattened->getHeaders());
$this->assertEquals(['Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'], $flattened->getHeaders());
$flattened = FlattenException::create(new ServiceUnavailableHttpException(120));
$this->assertEquals(array('Retry-After' => 120), $flattened->getHeaders());
$this->assertEquals(['Retry-After' => 120], $flattened->getHeaders());
$flattened = FlattenException::create(new TooManyRequestsHttpException('Fri, 31 Dec 1999 23:59:59 GMT'));
$this->assertEquals(array('Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'), $flattened->getHeaders());
$this->assertEquals(['Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'], $flattened->getHeaders());
$flattened = FlattenException::create(new TooManyRequestsHttpException(120));
$this->assertEquals(array('Retry-After' => 120), $flattened->getHeaders());
$this->assertEquals(['Retry-After' => 120], $flattened->getHeaders());
}
/**
@@ -162,7 +162,7 @@ class FlattenExceptionTest extends TestCase
$this->assertSame($flattened2, $flattened->getPrevious());
$this->assertSame(array($flattened2), $flattened->getAllPrevious());
$this->assertSame([$flattened2], $flattened->getAllPrevious());
}
public function testPreviousError()
@@ -200,18 +200,18 @@ class FlattenExceptionTest extends TestCase
public function testToArray(\Throwable $exception, string $expectedClass)
{
$flattened = FlattenException::createFromThrowable($exception);
$flattened->setTrace(array(), 'foo.php', 123);
$flattened->setTrace([], 'foo.php', 123);
$this->assertEquals(array(
array(
$this->assertEquals([
[
'message' => 'test',
'class' => $expectedClass,
'trace' => array(array(
'trace' => [[
'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '', 'file' => 'foo.php', 'line' => 123,
'args' => array(),
)),
),
), $flattened->toArray());
'args' => [],
]],
],
], $flattened->toArray());
}
public function testCreate()
@@ -229,10 +229,10 @@ class FlattenExceptionTest extends TestCase
public function flattenDataProvider()
{
return array(
array(new \Exception('test', 123), 'Exception'),
array(new \Error('test', 123), 'Error'),
);
return [
[new \Exception('test', 123), 'Exception'],
[new \Error('test', 123), 'Error'],
];
}
public function testArguments()
@@ -242,15 +242,15 @@ class FlattenExceptionTest extends TestCase
$incomplete = unserialize('O:14:"BogusTestClass":0:{}');
$exception = $this->createException(array(
(object) array('foo' => 1),
$exception = $this->createException([
(object) ['foo' => 1],
new NotFoundHttpException(),
$incomplete,
$dh,
$fh,
function () {},
array(1, 2),
array('foo' => 123),
[1, 2],
['foo' => 123],
null,
true,
false,
@@ -260,7 +260,7 @@ class FlattenExceptionTest extends TestCase
'',
INF,
NAN,
));
]);
$flattened = FlattenException::create($exception);
$trace = $flattened->getTrace();
@@ -271,26 +271,26 @@ class FlattenExceptionTest extends TestCase
fclose($fh);
$i = 0;
$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', 'stream'), $array[$i++]);
$this->assertSame(array('resource', 'stream'), $array[$i++]);
$this->assertSame(['object', 'stdClass'], $array[$i++]);
$this->assertSame(['object', 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException'], $array[$i++]);
$this->assertSame(['incomplete-object', 'BogusTestClass'], $array[$i++]);
$this->assertSame(['resource', 'stream'], $array[$i++]);
$this->assertSame(['resource', 'stream'], $array[$i++]);
$args = $array[$i++];
$this->assertSame($args[0], 'object');
$this->assertTrue('Closure' === $args[1] || is_subclass_of($args[1], '\Closure'), 'Expect object class name to be Closure or a subclass of Closure.');
$this->assertSame(array('array', array(array('integer', 1), array('integer', 2))), $array[$i++]);
$this->assertSame(array('array', array('foo' => array('integer', 123))), $array[$i++]);
$this->assertSame(array('null', null), $array[$i++]);
$this->assertSame(array('boolean', true), $array[$i++]);
$this->assertSame(array('boolean', false), $array[$i++]);
$this->assertSame(array('integer', 0), $array[$i++]);
$this->assertSame(array('float', 0.0), $array[$i++]);
$this->assertSame(array('string', '0'), $array[$i++]);
$this->assertSame(array('string', ''), $array[$i++]);
$this->assertSame(array('float', INF), $array[$i++]);
$this->assertSame(['array', [['integer', 1], ['integer', 2]]], $array[$i++]);
$this->assertSame(['array', ['foo' => ['integer', 123]]], $array[$i++]);
$this->assertSame(['null', null], $array[$i++]);
$this->assertSame(['boolean', true], $array[$i++]);
$this->assertSame(['boolean', false], $array[$i++]);
$this->assertSame(['integer', 0], $array[$i++]);
$this->assertSame(['float', 0.0], $array[$i++]);
$this->assertSame(['string', '0'], $array[$i++]);
$this->assertSame(['string', ''], $array[$i++]);
$this->assertSame(['float', INF], $array[$i++]);
// assertEquals() does not like NAN values.
$this->assertEquals($array[$i][0], 'float');
@@ -300,7 +300,7 @@ class FlattenExceptionTest extends TestCase
public function testRecursionInArguments()
{
$a = null;
$a = array('foo', array(2, &$a));
$a = ['foo', [2, &$a]];
$exception = $this->createException($a);
$flattened = FlattenException::create($exception);
@@ -310,7 +310,7 @@ class FlattenExceptionTest extends TestCase
public function testTooBigArray()
{
$a = array();
$a = [];
for ($i = 0; $i < 20; ++$i) {
for ($j = 0; $j < 50; ++$j) {
for ($k = 0; $k < 10; ++$k) {
@@ -325,7 +325,7 @@ class FlattenExceptionTest extends TestCase
$flattened = FlattenException::create($exception);
$trace = $flattened->getTrace();
$this->assertSame($trace[1]['args'][0], array('array', array('array', '*SKIPPED over 10000 entries*')));
$this->assertSame($trace[1]['args'][0], ['array', ['array', '*SKIPPED over 10000 entries*']]);
$serializeTrace = serialize($trace);
@@ -333,6 +333,19 @@ class FlattenExceptionTest extends TestCase
$this->assertNotContains('*value1*', $serializeTrace);
}
public function testAnonymousClass()
{
$flattened = FlattenException::create(new class() extends \RuntimeException {
});
$this->assertSame('RuntimeException@anonymous', $flattened->getClass());
$flattened = FlattenException::create(new \Exception(sprintf('Class "%s" blah.', \get_class(new class() extends \RuntimeException {
}))));
$this->assertSame('Class "RuntimeException@anonymous" blah.', $flattened->getMessage());
}
private function createException($foo)
{
return new \Exception();

View File

@@ -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';
@@ -62,10 +62,10 @@ class ExceptionHandlerTest extends TestCase
$this->assertContains('Sorry, the page you are looking for could not be found.', $response);
$expectedHeaders = array(
array('HTTP/1.0 404', true, null),
array('Content-Type: text/html; charset=iso8859-1', true, null),
);
$expectedHeaders = [
['HTTP/1.0 404', true, null],
['Content-Type: text/html; charset=iso8859-1', true, null],
];
$this->assertSame($expectedHeaders, testHeader());
}
@@ -75,14 +75,14 @@ class ExceptionHandlerTest extends TestCase
$handler = new ExceptionHandler(false, 'iso8859-1');
ob_start();
$handler->sendPhpResponse(new MethodNotAllowedHttpException(array('POST')));
$handler->sendPhpResponse(new MethodNotAllowedHttpException(['POST']));
$response = ob_get_clean();
$expectedHeaders = array(
array('HTTP/1.0 405', true, null),
array('Allow: POST', false, null),
array('Content-Type: text/html; charset=iso8859-1', true, null),
);
$expectedHeaders = [
['HTTP/1.0 405', true, null],
['Allow: POST', false, null],
['Content-Type: text/html; charset=iso8859-1', true, null],
];
$this->assertSame($expectedHeaders, testHeader());
}
@@ -101,7 +101,7 @@ class ExceptionHandlerTest extends TestCase
{
$exception = new \Exception('foo');
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(array('sendPhpResponse'))->getMock();
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(['sendPhpResponse'])->getMock();
$handler
->expects($this->exactly(2))
->method('sendPhpResponse');
@@ -119,7 +119,7 @@ class ExceptionHandlerTest extends TestCase
{
$exception = new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__);
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(array('sendPhpResponse'))->getMock();
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(['sendPhpResponse'])->getMock();
$handler
->expects($this->once())
->method('sendPhpResponse');

View File

@@ -11,18 +11,18 @@
namespace Symfony\Component\Debug\Tests\FatalErrorHandler;
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;
use Symfony\Component\Debug\DebugClassLoader;
use Composer\Autoload\ClassLoader as ComposerClassLoader;
class ClassNotFoundFatalErrorHandlerTest extends TestCase
{
public static function setUpBeforeClass()
{
foreach (spl_autoload_functions() as $function) {
if (!is_array($function)) {
if (!\is_array($function)) {
continue;
}
@@ -32,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;
}
}
@@ -72,85 +72,85 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
$autoloader = new ComposerClassLoader();
$autoloader->add('Symfony\Component\Debug\Exception\\', realpath(__DIR__.'/../../Exception'));
$debugClassLoader = new DebugClassLoader(array($autoloader, 'loadClass'));
$debugClassLoader = new DebugClassLoader([$autoloader, 'loadClass']);
return array(
array(
array(
return [
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'WhizBangFactory\' not found',
),
],
"Attempted to load class \"WhizBangFactory\" from the global namespace.\nDid you forget a \"use\" statement?",
),
array(
array(
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\WhizBangFactory\' not found',
),
],
"Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\Bar\".\nDid you forget a \"use\" statement for another namespace?",
),
array(
array(
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'UndefinedFunctionException\' not found',
),
],
"Attempted to load class \"UndefinedFunctionException\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
),
array(
array(
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'PEARClass\' not found',
),
],
"Attempted to load class \"PEARClass\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony_Component_Debug_Tests_Fixtures_PEARClass\"?",
),
array(
array(
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'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(
array(
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'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($autoloader, 'loadClass'),
),
array(
array(
[$autoloader, 'loadClass'],
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'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($debugClassLoader, 'loadClass'),
),
array(
array(
[$debugClassLoader, 'loadClass'],
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
),
],
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\Bar\".\nDid you forget a \"use\" statement for another namespace?",
function ($className) { /* do nothing here */ },
),
);
],
];
}
public function testCannotRedeclareClass()
@@ -161,12 +161,12 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
require_once __DIR__.'/../FIXTURES2/REQUIREDTWICE.PHP';
$error = array(
$error = [
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\RequiredTwice\' not found',
);
];
$handler = new ClassNotFoundFatalErrorHandler();
$exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line']));

View File

@@ -35,44 +35,44 @@ class UndefinedFunctionFatalErrorHandlerTest extends TestCase
public function provideUndefinedFunctionData()
{
return array(
array(
array(
return [
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Call to undefined function test_namespaced_function()',
),
],
"Attempted to call function \"test_namespaced_function\" from the global namespace.\nDid you mean to call \"\\symfony\\component\\debug\\tests\\fatalerrorhandler\\test_namespaced_function\"?",
),
array(
array(
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Call to undefined function Foo\\Bar\\Baz\\test_namespaced_function()',
),
],
"Attempted to call function \"test_namespaced_function\" from namespace \"Foo\\Bar\\Baz\".\nDid you mean to call \"\\symfony\\component\\debug\\tests\\fatalerrorhandler\\test_namespaced_function\"?",
),
array(
array(
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Call to undefined function foo()',
),
],
'Attempted to call function "foo" from the global namespace.',
),
array(
array(
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Call to undefined function Foo\\Bar\\Baz\\foo()',
),
],
'Attempted to call function "foo" from namespace "Foo\Bar\Baz".',
),
);
],
];
}
}

View File

@@ -34,43 +34,43 @@ class UndefinedMethodFatalErrorHandlerTest extends TestCase
public function provideUndefinedMethodData()
{
return array(
array(
array(
return [
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Call to undefined method SplObjectStorage::what()',
),
],
'Attempted to call an undefined method named "what" of class "SplObjectStorage".',
),
array(
array(
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Call to undefined method SplObjectStorage::walid()',
),
],
"Attempted to call an undefined method named \"walid\" of class \"SplObjectStorage\".\nDid you mean to call \"valid\"?",
),
array(
array(
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Call to undefined method SplObjectStorage::offsetFet()',
),
],
"Attempted to call an undefined method named \"offsetFet\" of class \"SplObjectStorage\".\nDid you mean to call e.g. \"offsetGet\", \"offsetSet\" or \"offsetUnset\"?",
),
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".',
),
);
],
];
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
class ClassWithAnnotatedParameters
{
/**
* @param string $foo this is a foo parameter
*/
public function fooMethod(string $foo)
{
}
/**
* @param string $bar parameter not implemented yet
*/
public function barMethod(/* string $bar = null */)
{
}
/**
* @param Quz $quz parameter not implemented yet
*/
public function quzMethod(/* Quz $quz = null */)
{
}
/**
* @param true $yes
*/
public function isSymfony()
{
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
eval('
namespace Symfony\Component\Debug\Tests\Fixtures;
class DefinitionInEvaluatedCode
{
}
');

View File

@@ -0,0 +1,22 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
class ErrorHandlerThatUsesThePreviousOne
{
private static $previous;
public static function register()
{
$handler = new static();
self::$previous = set_error_handler([$handler, 'handleError']);
return $handler;
}
public function handleError($type, $message, $file, $line, $context)
{
return \call_user_func(self::$previous, $type, $message, $file, $line, $context);
}
}

View File

@@ -4,6 +4,8 @@ namespace Symfony\Component\Debug\Tests\Fixtures;
class ExtendedFinalMethod extends FinalMethod
{
use FinalMethod2Trait;
/**
* {@inheritdoc}
*/

View File

@@ -1,10 +0,0 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
/**
* @final
*/
class FinalClass
{
}

View File

@@ -0,0 +1,85 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
/**
* @final since version 3.3.
*/
class FinalClass1
{
// simple comment
}
/**
* @final
*/
class FinalClass2
{
// no comment
}
/**
* @final comment with @@@ and ***
*
* @author John Doe
*/
class FinalClass3
{
// with comment and a tag after
}
/**
* @final
*
* @author John Doe
*/
class FinalClass4
{
// without comment and a tag after
}
/**
* @author John Doe
*
*
* @final multiline
* comment
*/
class FinalClass5
{
// with comment and a tag before
}
/**
* @author John Doe
*
* @final
*/
class FinalClass6
{
// without comment and a tag before
}
/**
* @author John Doe
*
* @final another
* multiline comment...
*
* @return string
*/
class FinalClass7
{
// with comment and a tag before and after
}
/**
* @author John Doe
* @final
*
* @return string
*/
class FinalClass8
{
// without comment and a tag before and after
}

View File

@@ -11,6 +11,15 @@ class FinalMethod
{
}
/**
* @final
*
* @return int
*/
public function finalMethod2()
{
}
public function anotherMethod()
{
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
trait FinalMethod2Trait
{
public function finalMethod2()
{
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
/**
* Ensures a deprecation is triggered when a new parameter is not declared in child classes.
*/
interface InterfaceWithAnnotatedParameters
{
/**
* @param bool $matrix
*/
public function whereAmI();
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
use Symfony\Component\Debug\BufferingLogger;
class LoggerThatSetAnErrorHandler extends BufferingLogger
{
public function log($level, $message, array $context = [])
{
set_error_handler('is_string');
parent::log($level, $message, $context);
restore_error_handler();
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
class SubClassWithAnnotatedParameters extends ClassWithAnnotatedParameters implements InterfaceWithAnnotatedParameters
{
use TraitWithAnnotatedParameters;
public function fooMethod(string $foo)
{
}
public function barMethod($bar = null)
{
}
public function quzMethod()
{
}
public function whereAmI()
{
}
}

View File

@@ -18,7 +18,7 @@ class ToStringThrower
} catch (\Exception $e) {
// Using user_error() here is on purpose so we do not forget
// that this alias also should work alongside with trigger_error().
return user_error($e, E_USER_ERROR);
return trigger_error($e, E_USER_ERROR);
}
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
trait TraitWithAnnotatedParameters
{
/**
* `@param` annotations in traits are not parsed.
*/
public function isSymfony()
{
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
trait TraitWithInternalMethod
{
/**
* @internal
*/
public function foo()
{
}
}

View File

@@ -25,14 +25,14 @@ namespace Symfony\Component\Debug\Tests;
function testHeader()
{
static $headers = array();
static $headers = [];
if (!$h = func_get_args()) {
if (!$h = \func_get_args()) {
$h = $headers;
$headers = array();
$headers = [];
return $h;
}
$headers[] = func_get_args();
$headers[] = \func_get_args();
}

View File

@@ -9,7 +9,7 @@ use Symfony\Component\Debug\DebugClassLoader;
$vendor = __DIR__;
while (!file_exists($vendor.'/vendor')) {
$vendor = dirname($vendor);
$vendor = \dirname($vendor);
}
require $vendor.'/vendor/autoload.php';
@@ -24,3 +24,4 @@ class_exists(ExtendedFinalMethod::class);
?>
--EXPECTF--
The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" 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".
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".

View File

@@ -1,5 +1,7 @@
--TEST--
Test catching fatal errors when handlers are nested
--INI--
display_errors=0
--FILE--
<?php
@@ -7,7 +9,7 @@ namespace Symfony\Component\Debug;
$vendor = __DIR__;
while (!file_exists($vendor.'/vendor')) {
$vendor = dirname($vendor);
$vendor = \dirname($vendor);
}
require $vendor.'/vendor/autoload.php';
@@ -24,7 +26,6 @@ if (true) {
?>
--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".
@@ -38,8 +39,7 @@ Did you forget a "use" statement for another namespace?"
["line":protected]=>
int(%d)
["trace":"Exception":private]=>
array(0) {
}
array(%d) {%A}
["previous":"Exception":private]=>
NULL
["severity":protected]=>

View File

@@ -7,14 +7,14 @@ namespace Symfony\Component\Debug;
$vendor = __DIR__;
while (!file_exists($vendor.'/vendor')) {
$vendor = dirname($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())
public function log($level, $message, array $context = [])
{
echo $message, "\n";
}

View File

@@ -7,7 +7,7 @@ namespace Symfony\Component\Debug;
$vendor = __DIR__;
while (!file_exists($vendor.'/vendor')) {
$vendor = dirname($vendor);
$vendor = \dirname($vendor);
}
require $vendor.'/vendor/autoload.php';
@@ -17,9 +17,9 @@ ini_set('display_errors', 0);
$eHandler = set_error_handler('var_dump');
$xHandler = set_exception_handler('var_dump');
var_dump(array(
var_dump([
$eHandler[0] === $xHandler[0] ? 'Error and exception handlers do match' : 'Error and exception handlers are different',
));
]);
$eHandler[0]->setExceptionHandler('print_r');

View File

@@ -34,7 +34,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
"dev-master": "4.2-dev"
}
}
}

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"