Compare commits

..

56 Commits

Author SHA1 Message Date
Nicolas Grekas
4e7c98de67 Merge branch '3.4' into 4.0
* 3.4:
  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
  [DI] Display previous error messages when throwing unused bindings
  Suppress warnings when open_basedir is non-empty
2018-05-16 11:05:32 +02:00
Fabien Potencier
4afe1548f3 fixed CS 2018-05-11 17:58:37 +02:00
Nicolas Grekas
e1d57cdb35 Merge branch '3.4' into 4.0
* 3.4:
  [Debug][WebProfilerBundle] Fix setting file link format
  [Debug] Fixed the formatPath when a custom fileLinkFormat is defined
2018-04-30 09:59:37 -07:00
Fabien Potencier
5961d02d48 Merge branch '3.4' into 4.0
* 3.4:
  [Yaml] Fix regression when trying to parse multiline
  Add PHPDbg support to HTTP components
  bumped Symfony version to 2.8.38
  updated VERSION for 2.8.37
  updated CHANGELOG for 2.8.37
  bumped Symfony version to 2.7.45
  updated VERSION for 2.7.44
  update CONTRIBUTORS for 2.7.44
  updated CHANGELOG for 2.7.44
  Fix check of color support on Windows
2018-04-03 07:24:00 +02:00
Nicolas Grekas
af3b794316 Merge branch '3.4' into 4.0
* 3.4: (24 commits)
  moved Twig runtime to proper class
  fixed deprecated messages in tests
  add PHP errors options to XML schema definition
  [HttpCache] Unlink tmp file on error
  Added LB translation for #26327 (Errors sign for people that do not see colors)
  [TwigBridge] Fix rendering of currency by MoneyType
  Import InvalidArgumentException in PdoAdapter
  [DI] Do not suggest writing an implementation when multiple exist
  [Intl] Update ICU data to 61.1
  Use 3rd person verb form in command description
  [Validator] Add Japanese translation
  Support phpdbg SAPI in Debug::enable()
  [HttpKernel] DumpDataCollector: do not flush when a dumper is provided
  [DI] Fix hardcoded cache dir for warmups
  [Routing] fix tests
  [Routing] Fixed the importing of files using glob patterns that match multiple resources
  [Ldap] cast to string when checking empty passwords
  [Validator] sync validator translation id
  [WebProfilerBundle] use the router to resolve file links
  no type errors with invalid submitted data types
  ...
2018-04-02 11:52:41 +02:00
Nicolas Grekas
2e7937e541 Merge branch '3.4' into 4.0
* 3.4: (32 commits)
  [Form] fix tests and deps
  [Cache] Rely on mock for Doctrine ArrayCache
  [FrameworkBundle] Respect debug mode when warm up annotations
  [Console] Fix docblock of DescriptorInterface::describe
  [Config] Handle nullable node name + fix inheritdocs
  [Security] added userChecker to SimpleAuthenticationProvider
  [Debug] fix test
  Fix typo in test method name
  Fixes #26563 (open_basedir restriction in effect)
  [Debug] Reset previous exception handler ealier to prevent infinite loop
  add hint in Github pull request template
  [Validator] Fix docblock of ClassMetadata#members
  [BrowserKit] Fix cookie path handling when $domain is null
  [DoctrineBridge] Don't rely on ClassMetadataInfo->hasField in DoctrineOrmTypeGuesser anymore
  [BrowserKit] Improves CookieJar::get
  [BrowserKit] Fix Cookie's PHPDoc
  [DomCrawler] Change bad wording in ChoiceFormField::untick
  [DomCrawler] Fix the PHPDoc of ChoiceFormField::setValue
  [DomCrawler] Avoid a useless call to strtolower
  [FrameworkBundle] HttpCache is not longer abstract
  ...
2018-03-19 23:35:49 +01:00
Fabien Potencier
1721e4e7ef Merge branch '3.4' into 4.0
* 3.4:
  [Form][WCAG] Add hidden labels on date and time fields
  Pass on previous exception in FatalThrowableError
  [Routing] remove dead code
  [Routing] fix typo
  [Form][WCAG] Fixed HTML errors
  fix merge
  [FrameworkBundle] [Console] add a warning when command is not found
  [WebProfilerBundle] limit ajax request to 100 and remove the last one
2018-02-28 13:50:02 -08:00
Fabien Potencier
aec0ebd6c2 removed version in @final @internal for version < 4.0 2018-02-19 13:18:43 +01:00
Nicolas Grekas
cc2522bfc8 Merge branch '3.4' into 4.0
* 3.4:
  [CssSelector] For AND operator, the left operand should have parentheses, not only right operand
  Removed unused parameter from flattenDataProvider().
  Update MongoDB extension on travis to make the builds green again.
2018-02-03 15:58:37 +01:00
Robin Chalas
57405e340d Merge branch '3.4' into 4.0
* 3.4:
  [Intl] Fixed the broken link
  Fix typo
  Fix typo
  Fixed issue #25985
  Don't show wanna-be-private services as public in debug:container
  [Routing] Fix trailing slash redirection for non-safe verbs
  [DI] Fix tracking of source class changes for lazy-proxies
  Proxy class names should be deterministic and independent of spl_object_hash() which is somewhat random
  [Debug] Fix bad registration of exception handler, leading to mem leak
  [Form] Fixed empty data on expanded ChoiceType and FileType
  collect extension information as late as possible
2018-02-03 01:57:23 +01:00
Nicolas Grekas
c77bb31d0f Merge branch '3.4' into 4.0
* 3.4:
  [HttpKernel] DebugHandlersListener should always replace the existing exception handler
  fix the Composer API being used
  [Security] Notify that symfony/expression-language is not installed if ExpressionLanguage and ExpressionLanguagePrivider are used
  [Debug] Always decorate existing exception handlers to deal with fatal errors
  Enableable ArrayNodeDefinition is disabled for empty configuration
  Fixing a bug where the dump() function depended on bundle ordering
  [Cache] Fix handling of apcu_fetch() edgy behavior
  Add nn (Norwegian Nynorsk) translation files, and improve existing file
  Problem in phar see mergerequest #25579
  [Form] Disallow transform dates beyond the year 9999
  Avoid button label translation when it's set to false
  Copied NO language files to the new NB locale.
  [Serializer] DateTimeNormalizer handling of null and empty values (returning null or empty instead of new object)
  Fix options resolver with array allowed types
  [Console] Improve phpdoc on StyleInterface::ask()
  [TwigBridge][WIP] Pass the form-check-inline in parent
2018-01-18 23:19:33 +01:00
Nicolas Grekas
1e7a70e8b8 Merge branch '3.4' into 4.0
* 3.4:
  fix merge
  fixed wrong description in a phpdoc
  19 digits VISA card numbers are valid
  Add missing @ in phpdoc return statement
  Don't right trim the deprecation message
  [HttpKernel] Fixed test name
  [Debug] prevent infinite loop with faulty exception handlers
  [FrameworkBundle] fix tests
  Prefer composer install instead for using Symfony Installer
  Add the missing `enabled` session attribute
  [HttpKernel] Turn bad hosts into 400 instead of 500
2018-01-13 15:05:32 +01:00
Nicolas Grekas
9ae4223a66 Merge branch '3.4' into 4.0
* 3.4:
  PHP CS Fixer: clean up repo and adjust config
  use interface_exists instead of class_exists
  [DX] [DI] Improve exception for invalid setter injection arguments
  Dumper shouldn't use html format for phpdbg
  [Validator] Fix access to root object when using composite constraint
2018-01-03 18:15:19 +01:00
Fabien Potencier
1c7ea2dc10 Merge branch '3.4' into 4.0
* 3.4:
  fixed years in copyright
  fix typo
2018-01-03 08:38:00 +01:00
Nicolas Grekas
e47555b8c0 Merge branch '3.4' into 4.0
* 3.4:
  Clean up
  Update return type in docblock.
  PHP CS Fixer: no need to exclude xml and yml files
  PHP CS Fixer: no need to exclude json file
  Update LICENSE year... forever
  fixed some deprecation messages
  fixed CS
  Fixes for Oracle in PdoSessionHandler
  fixed some deprecation messages
  fixed some deprecation messages
  fixed some deprecation messages
  fixed some deprecation messages
  [TwigBundle/Brige] catch missing requirements to throw meaningful exceptions
  [HttpKernel] Call Response->setPrivate() instead of sending raw header() when session is started
  [FrameworkBundle] Make cache:clear "atomic" and consistent with cache:warmup
  Suggest to write an implementation if the interface cannot be autowired
  [Debug] Skip DebugClassLoader checks for already parsed files
  [2.7][DX] Use constant message contextualisation for deprecations
  Remove group options without data and fix normalization
  Remove redundant translation path
2018-01-02 17:33:53 +01:00
Nicolas Grekas
20dce5f101 Merge branch '3.4' into 4.0
* 3.4:
  [2.7] Fix issues found by PHPStan
  [Command] Fix upgrade guide example
  Add php_unit_dedicate_assert to PHPCS
  [WebProfilerBundle] Let fetch() cast URL to string
  improve FormType::getType exception message details
  [Intl] Update ICU data to 60.2
  [Console] fix a bug when you are passing a default value and passing -n would ouput the index
  [FrameworkBundle] fix merge of 3.3 into 3.4
  bumped Symfony version to 3.4.3
  updated VERSION for 3.4.2
  updated CHANGELOG for 3.4.2
2017-12-20 12:09:53 +01:00
Nicolas Grekas
8c3e709209 Merge branch '3.4' into 4.0
* 3.4: (22 commits)
  fix merge
  [Translation] Fix InvalidArgumentException when using untranslated plural forms from .po files
  Fixed exit code with non-integer throwable code
  [HttpFoundation] Support 0 bit netmask in IPv6 ()
  [DI] Impossible to set an environment variable and then an array as container parameter
  [Process] remove false-positive BC breaking exception on Windows
  Tweaking class not found autowiring error
  [LDAP] added missing dots at the end of some exception messages.
  [TwigBridge] Add missing dev requirement for workflow
  fixed #25440
  empty lines don't count for indent detection
  Set `width: auto` on WebProfiler toolbar's reset.
  [Lock] Fix incorrect phpdoc
  [Process] Dont rely on putenv(), it fails on ZTS PHP
  [HttpKernel] detect deprecations thrown by container initialization during tests
  [HttpKernel] Fix logging of post-terminate errors/exceptions
  [DI] Add context to service-not-found exceptions thrown by service locators
  [Debug] Fix catching fatal errors in case of nested error handlers
  [VarDumper] Fixed file links leave blank pages when ide is configured
  Fix hidden currency element with Bootstrap 3 theme
  ...
2017-12-12 09:41:51 +01:00
Nicolas Grekas
26a15dab86 Merge branch '3.4'
* 3.4:
  [Debug] Fix undefined variable $lightTrace
  [Bridge/PhpUnit] fix installation path
2017-11-21 10:27:49 +01:00
Nicolas Grekas
a5069bdba7 Merge branch '3.4'
* 3.4:
  [Bridge/PhpUnit] Fix compat with phpunit 4.8 & bridge <=3.3.13
  Move deprecation under use statements
  Remove function_exists(__phpunit_run_isolated_test) checks
2017-11-19 22:10:49 +02:00
Nicolas Grekas
92697a71cd Merge branch '3.4'
* 3.4:
  [TwigBridge] Fixed the .form-check-input class in the bs4 templates
  [Console] Fix traversable autocomplete values
  [SecurityBundle] Improve deprecations
  [DI] Friendlier name for generated container in "as_files" mode
  [Debug] Remove false-positive deprecation from DebugClassLoader
  [SecurityBundle] Add missing quotes in deprecation messages
  [ExpressionLanguage] Fix PhpDoc type-hints on Token value
  bumped Symfony version to 3.3.12
  Add default translations path option and convention
  updated VERSION for 3.3.11
  updated CHANGELOG for 3.3.11
  bumped Symfony version to 2.8.30
  updated VERSION for 2.8.29
  updated CHANGELOG for 2.8.29
  bumped Symfony version to 2.7.37
  updated VERSION for 2.7.36
  update CONTRIBUTORS for 2.7.36
  updated CHANGELOG for 2.7.36
2017-11-12 17:47:31 +01:00
Nicolas Grekas
ca8a6e958e Merge branch '3.4'
* 3.4: (21 commits)
  fixed CS
  HttpCache lock update
  [Intl] Update ICU data to 60.1
  [YAML] Allow to parse custom tags when linting yaml files
  [HttpKernel][Debug] Remove noise from stack frames of deprecations
  [WebServerBundle] prevent console.terminate from being fired after stopping server
  [Validator] Fix Costa Rica IBAN format
  [Bridge/ProxyManager] Remove direct reference to value holder property
  [Validator] Add Belarus IBAN format
  [Config] Fix cannotBeEmpty()
  [Debug] More aggressively aggregate silenced notices per file+line
  [HttpFoundation] minor session-related fix
  [Cache][Lock] Add RedisProxy for lazy Redis connections
  [TwigBridge] [Bootstrap 4] Fix validation error design for expanded choiceType
  [FrameworkBundle] Specifically inject the debug dispatcher in the collector
  [WebserverBundle] fixed the bug that caused that the webserver would …
  update the pull request template
  [Stopwatch] minor fix
  Add default mapping path for validator component
  Add default mapping path for serializer component
  ...
2017-11-10 20:37:45 +01:00
Nicolas Grekas
d61d1eb839 Replace more docblocks by type-hints 2017-11-07 15:45:01 +01:00
Nicolas Grekas
a5bb97fb9f Merge branch '3.4'
* 3.4:
  [DI] minor docblock fixes
2017-10-24 16:16:56 +02:00
Nicolas Grekas
c8e7639261 Merge branch '3.4'
* 3.4: (26 commits)
  [Routing] Fix resource miss
  [Security] Fixed auth provider authenticate() cannot return void
  [FrameworkBundle][Serializer] Move DateIntervalNormalizer definition to xml
  declare argument type
  Improving annotation loader message
  [FrameworkBundle][Serializer] Move normalizer/encoders definitions to xml file & remove unnecessary checks
  Update UPGRADE-4.0.md
  streamed response should return $this
  $isClientIpsVali is not used
  [WebServerBundle] Prevent commands from being registered by convention
  content can be a resource
  Adding the Form default theme files to be warmed up in Twig's cache
  Remove BC Break label from `NullDumper` class
  Username and password in basic auth are allowed to contain '.'
  Remove obsolete PHPDoc from UriSigner
  [Serializer] YamlEncoder: throw if the Yaml component isn't installed
  [Serializer] ObjectNormalizer: throw if PropertyAccess isn't installed
  [PropertyInfo] Add support for the iterable type
  pdo session fix
  Fixed pathinfo calculation for requests starting with a question mark.  - fix bad conflict resolving issue  - port symfony/symfony#21968 to 3.3+
  ...
2017-10-20 12:28:39 -07:00
Nicolas Grekas
a76f02e3af Merge branch '3.4'
* 3.4:
  fix merge
  fix merge
  [FORM] Prevent forms from extending itself as a parent
  fix merge
  Fix 7.2 compat layer
  [DI] Prefixed env vars and load time inlining are incompatible
  bug #24499 [Bridge\PhpUnit] Fix infinite loop when running isolated method (bis) (nicolas-grekas)
  Fix PHP 7.2 support
  [HttpFoundation] Add missing session.lazy_write config option
  [DI] Exclude inline services declared in XML from autowiring candidates
  [HttpFoundation] Combine Cache-Control headers
  [Form] fix parsing invalid floating point numbers
  Escape command usage when displaying it in the text descriptor
  [DI] Throw accurate failures when accessing removed services
  [DI] Turn private defs to non-public ones before removing passes
  Use for=ID on radio/checkbox label.
2017-10-10 16:32:10 +02:00
Nicolas Grekas
61c2bb6dc9 Merge branch '3.4'
* 3.4: (33 commits)
  Remove remaining `@experimental` annotations
  Tests and fix for issue in array model data in EntityType field with multiple=true
  [Validator] Add unique entity violation cause
  [Lock] Automaticaly release lock when user forget it
  [Form] Fixed PercentToLocalizedStringTransformer to accept both comma and dot as decimal separator, if possible
  fixed CS
  [FrameworkBundle] Don't clear app pools on cache:clear
  Hide label button when its setted to false
  removed useless PHPDoc
  [HttpFoundation] Return instance in StreamedResponse
  [Form] Fix FormInterface::submit() annotation
  [PHPUnitBridge] don't remove when set to  empty string
  PdoSessionHandler: fix advisory lock for pgsql when session.sid_bits_per_character > 4
  HttpCache does not consider ESI resources in HEAD requests
  Fix translation for "This field was not expected"
  [Routing] Enhance Route(Collection) docblocks
  Added improvement for accuracy in MoneyToLocalizedStringTransformer.
  Removed unused private property
  Use correct verb form in the pull request template
  Use PHP_MAXPATHLEN in Filesystem.
  ...
2017-10-02 08:59:24 +02:00
Fabien Potencier
82a670d33f Merge branch '3.4'
* 3.4:
  Display form defaults on debug:form
  [Serializer][FrameworkBundle] Add a DateInterval normalizer
  fix merge
  CS: recover no_break_comment
  [DI] Fix non-instantiables auto-discovery
2017-09-15 10:31:55 -07:00
Nicolas Grekas
70e9d372ae Merge branch '3.4'
* 3.4:
  [CS][2.7] yoda_style, no_unneeded_curly_braces, no_unneeded_final_method, semicolon_after_instruction
  Reset stopwatch.
  [Filesystem] mirror - fix copying content with same name as source/target.
  Removed unnecessary getDefinition() call.
  .php_cs.dist - simplify config
  [WebProfilerBundle] fixed TemplateManager when using Twig 2 without compat interfaces
2017-09-15 12:16:43 +02:00
Nicolas Grekas
970ca21e12 Merge branch '3.3' into 3.4
* 3.3:
  [CS][2.7] yoda_style, no_unneeded_curly_braces, no_unneeded_final_method, semicolon_after_instruction
  [Filesystem] mirror - fix copying content with same name as source/target.
  Removed unnecessary getDefinition() call.
  .php_cs.dist - simplify config
  [WebProfilerBundle] fixed TemplateManager when using Twig 2 without compat interfaces
2017-09-15 12:12:22 +02:00
Nicolas Grekas
c5a160f3ba Merge branch '2.8' into 3.3
* 2.8:
  [CS][2.7] yoda_style, no_unneeded_curly_braces, no_unneeded_final_method, semicolon_after_instruction
  [Filesystem] mirror - fix copying content with same name as source/target.
  .php_cs.dist - simplify config
  [WebProfilerBundle] fixed TemplateManager when using Twig 2 without compat interfaces
2017-09-15 12:08:59 +02:00
Christian Flothmann
ce79328087 Merge branch '3.4'
* 3.4:
  [Debug] fix test assertion
2017-09-12 12:12:59 +02:00
Fabien Potencier
67c2aa7896 Merge branch '3.4'
* 3.4:
  fixed CS
  fixed CS
  fixed CS
2017-09-11 14:36:26 -07:00
Fabien Potencier
1eb7f04f24 Merge branch '3.4'
* 3.4:
  [CS] Apply phpdoc_annotation_without_dot
  bumped Symfony version to 3.3.10
  updated VERSION for 3.3.9
  updated CHANGELOG for 3.3.9
  [DomCrawler] Fix conversion to int on GetPhpFiles
  Remove `protected_to_private` rule.
  Filtering empty uuids in ORMQueryBuilderLoader.
2017-09-11 13:45:27 -07:00
Nicolas Grekas
96bc445c20 Merge branch '3.4'
* 3.4:
  [HttpKernel] Deprecate EnvParametersResource
  [Lock] Check TTL expiration in lock acquisition
  Fix race condition in tests between cache and lock
  Improved how links are displayed in exception messages
2017-09-03 16:49:52 +02:00
Robin Chalas
09d2d7c077 Merge branch '3.4'
* 3.4: (38 commits)
  Fix merge
  [Lock] Expose an expiringDate and isExpired method in Lock
  [VarDumper] fix DateCasterTest
  [config] Add ability to deprecate a node
  feature #22382 [config] Add abbitily to deprecate a node (Nyholm, fabpot, sanpii)
  Fix segfault in period caster
  Create an interface for TranslationReader and moved TranslationLoader to Translation component
  Always require symfony/polyfill-apcu to provide APCuIterator everywhere
  [Lock] Fix some tests that require pcntl_sigwaitinfo() function
  bumped Symfony version to 3.3.9
  updated VERSION for 3.3.8
  updated CHANGELOG for 3.3.8
  [DI] Fix tracking env var placeholders nested in object graphs
  bumped Symfony version to 3.3.8
  updated VERSION for 3.3.7
  updated CHANGELOG for 3.3.7
  Add period caster
  [DI] improve psr4-based service discovery with namespace option
  [DI] Fix tracking env vars when merging configs (bis)
  removed obsolete comment
  ...
2017-08-30 01:06:25 +02:00
Nicolas Grekas
07bc974dbe Merge branch '3.4'
* 3.4: (23 commits)
  [DI] Allow dumping inline services in Yaml
  fixed CS
  [2.8] Modify 2.8 upgrade doc - key option is deprecated.
  Fix lock failling test
  [Debug] Correctly detect methods not from the same vendor
  [HttpKernel] Deprecated commands auto-registration
  Fix minors in date caster
  [FrameworkBundle] Catch Fatal errors in commands registration
  [Debug] Detect internal and deprecated methods
  [Profiler] Make the validator toolbar item consistent with the form one
  [DebugBundle] Reword an outdated comment about var dumper wiring
  updated CHANGELOG
  [HttpFoundation] Remove length limit on ETag
  [DI] Fix some docblocks
  [DI] Fix some docblocks
  Fixed the exception page design in responsive mode
  [Console] Log exit codes as debug messages instead of errors
  Fixed UPGRADE-4.0 about Container::set
  Ignore memcached missing key error on dession destroy
  [FrameworkBundle] Allow micro kernel to subscribe events easily
  ...
2017-08-10 16:21:53 +02:00
Nicolas Grekas
620550389a Merge branch '3.4'
* 3.4:
  [Debug] Trigger a deprecation when using an internal class/trait/interface
  [DI] Generate one file per service factory
2017-08-07 20:06:09 +02:00
Nicolas Grekas
56cb55542f Merge branch '3.4'
* 3.4:
  [DI] Remove unused props from the PhpDumper
  [VarDumper] Keep and reuse array stubs in memory
  [DI][ProxyManager] Pass the factory code to execute to DumperInterface::getProxyFactoryCode()
  [Workflow] Adding workflow name to the announce event
  [ProxyManager] Cleanup fixtures
  [Console][WebServerBundle] Use "exec" when possible
  [Debug] HTML-escape array key
  Add some phpdocs for IDE autocompletion and better SCA
  Fixed typo in docblock
2017-07-28 17:35:42 +02:00
Nicolas Grekas
15b0a06a42 Merge branch '3.4'
* 3.4:
  Minor cleanups
2017-07-06 16:37:40 +03:00
Nicolas Grekas
b76a3de8c5 feature #22804 [Debug] Removed ContextErrorException (mbabker)
This PR was merged into the 4.0-dev branch.

Discussion
----------

[Debug] Removed ContextErrorException

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | yes
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #21388
| License       | MIT
| Doc PR        | n/a

Commits
-------

76dc317 Removed ContextErrorException
2017-07-06 16:32:31 +03:00
Michael Babker
856a3e180b Removed ContextErrorException 2017-07-06 07:23:02 -05:00
Nicolas Grekas
78aeb1c848 Merge branch '3.4'
* 3.4:
  Deprecate support for stacked errors
  fixed tests
  [HttpFoundation] Find the original request protocol version
  fixed CS
  Add support for microseconds in Stopwatch
  Preserve HttpOnly value when deserializing a header
  add minimum and maximum amount of pixels to Image validator
  fixed CHANGELOG
  [DX] [TwigBundle] Enhance the new exception page design
  [BrowserKit] Emulate back/forward browser navigation
  Fix deprecated message
  [Component][Serializer][Normalizer] : Deal it with Has Method for the Normalizer/Denormalizer
  [Validator] improve the changelog
  [FrameworkBundle] Wire inner translator
  [FrameworkBundle][HttpKernel] Move addcachearmer, addcacheclearer compiler pass
  [FrameworkBundle][Translation] Move translation compiler pass
2017-07-06 13:49:06 +03:00
Fabien Potencier
d11ca28ddc Merge branch '3.3'
* 3.3:
  [DI][Security] Prevent unwanted deprecation notices when using Expression Languages
  bumped Symfony version to 3.3.5
  updated VERSION for 3.3.4
  updated CHANGELOG for 3.3.4
  [VarDumper] Reduce size of serialized Data objects
  bumped Symfony version to 3.2.12
  updated VERSION for 3.2.11
  updated CHANGELOG for 3.2.11
  [DoctrineBridge] Use normalizedIds for resetting entity manager services
2017-07-06 09:25:25 +03:00
Nek (Maxime Veber)
78a5af2f68 Remove HHVM support (second edition) 2017-07-03 10:26:05 +03:00
Nicolas Grekas
2b1c9fd1e3 Merge branch '3.4'
* 3.4:
  [MonologBridge] Do not silence errors in ServerLogHandler::formatRecord
  bumped Symfony version to 3.3.3
  updated VERSION for 3.3.2
  updated CHANGELOG for 3.3.2
  [HttpKernel][Debug] Fix missing trace on deprecations collected during bootstrapping & silenced errors
  [PropertyInfo] Made ReflectionExtractor's prefix lists instance variables
2017-06-07 16:10:47 +02:00
Fabien Potencier
68792b216c removed HHVM support 2017-06-01 15:17:54 -07:00
Fabien Potencier
854252d112 Merge branch '3.4'
* 3.4: (31 commits)
  Using FQ name for PHP_VERSION_ID
  [EventDispatcher] Handle laziness internally instead of relying on ClosureProxyArgument
  Fix CacheCollectorPass priority
  [Form] Fix \IntlDateFormatter timezone parameter usage to bypass PHP bug #66323
  [Routing] Allow GET requests to be redirected. Fixes #23004
  [DI] Deal with inlined non-shared services
  [Cache] Ignore missing annotations.php
  [DI] Autowiring exception thrown when inlined service is removed
  Improving deprecation message when hitting the "deprecated type" lookup, but an alias is available
  Harden the debugging of Twig filters and functions
  Fixing a bug where an autowiring exception was thrown even when that service was removed
  Remove extra arg in call to TraceableAdapter::start()
  Support unknown compiler log format
  [Config] Allow empty globs
  Fix decorating TagAware adapters in dev
  [Profiler] Fix clicking on links inside toggle
  [Profiler] Fix text selection on exception pages
  bumped Symfony version to 3.3.1
  updated VERSION for 3.3.0
  updated CHANGELOG for 3.3.0
  ...
2017-06-01 14:04:19 -07:00
Nicolas Grekas
e2471c3c27 Merge branch '3.4'
* 3.4:
  typo
  Fixed options stub values display in form profiler
  [Console] Fix tests
  Make the simple exception pages match the new style
  [Console] Fixed different behaviour of key and value user inputs in multiple choice question
  Adjust PHPUnit class_alias check to also check for namespaced class
  [Cache] Dont use pipelining with RedisCluster
  [Yaml] fix colon without space deprecation
  [Intl] Fix intl tests for PHP < 5.5.10
2017-05-28 13:01:50 +02:00
Robin Chalas
00425e7ce6 CS Fixes 2017-05-22 11:03:40 +02:00
Maxime Steinhausser
2c92bb4d75 Remove PHP < 7.1.3 code 2017-05-22 08:50:05 +02:00
Christian Flothmann
c5b6e2628d [ClassLoader] remove the component
(cherry picked from commit c365ae2)
2017-05-21 12:04:58 +02:00
Nicolas Grekas
70a4a261d5 [Debug][VarDumper] Remove the symfony_debug C extension 2017-05-19 19:05:40 +02:00
Nicolas Grekas
7faa20c95d Tweak travis and appveyor for Symfony 4 2017-05-18 15:50:33 +02:00
Fabien Potencier
2803d2ea75 bumped minimum version to PHP 7.1 2017-05-18 14:57:29 +02:00
Nicolas Grekas
369b129a04 Merge branch '3.4'
* 3.4:
  Allow individual bridges, bundles and components to be used with 4.0
2017-05-18 14:56:38 +02:00
Fabien Potencier
c7a4bc2a59 updated version to 4.0 2017-05-17 18:33:00 +02:00
54 changed files with 795 additions and 2375 deletions

View File

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

View File

@@ -1,6 +1,12 @@
CHANGELOG
=========
4.0.0
-----
* removed the symfony_debug extension
* removed `ContextErrorException`
3.4.0
-----

View File

@@ -23,7 +23,7 @@ class Debug
/**
* Enables the debug tools.
*
* This method registers an error handler, an exception handler and a special class loader.
* This method registers an error handler and an exception handler.
*
* @param int $errorReportingLevel The level of error reporting you want
* @param bool $displayErrors Whether to display errors (for development) or just log them (for production)
@@ -42,10 +42,10 @@ class Debug
error_reporting(E_ALL);
}
if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
if (!\in_array(PHP_SAPI, array('cli', 'phpdbg'), true)) {
ini_set('display_errors', 0);
ExceptionHandler::register();
} elseif ($displayErrors && (!filter_var(ini_get('log_errors'), FILTER_VALIDATE_BOOLEAN) || ini_get('error_log'))) {
} elseif ($displayErrors && (!ini_get('log_errors') || ini_get('error_log'))) {
// CLI - display errors only if they're not already logged to STDERR
ini_set('display_errors', 1);
}

View File

@@ -26,25 +26,24 @@ class DebugClassLoader
{
private $classLoader;
private $isFinder;
private $loaded = [];
private $loaded = array();
private static $caseCheck;
private static $checkedClasses = [];
private static $final = [];
private static $finalMethods = [];
private static $deprecated = [];
private static $internal = [];
private static $internalMethods = [];
private static $php7Reserved = ['int' => 1, 'float' => 1, 'bool' => 1, 'string' => 1, 'true' => 1, 'false' => 1, 'null' => 1];
private static $darwinCache = ['/' => ['/', []]];
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()));
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);
@@ -53,7 +52,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')) {
@@ -85,7 +84,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;
}
@@ -94,8 +93,8 @@ class DebugClassLoader
}
foreach ($functions as $function) {
if (!\is_array($function) || !$function[0] instanceof self) {
$function = [new static($function), 'loadClass'];
if (!is_array($function) || !$function[0] instanceof self) {
$function = array(new static($function), 'loadClass');
}
spl_autoload_register($function);
@@ -107,7 +106,7 @@ class DebugClassLoader
*/
public static function disable()
{
if (!\is_array($functions = spl_autoload_functions())) {
if (!is_array($functions = spl_autoload_functions())) {
return;
}
@@ -116,7 +115,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();
}
@@ -124,19 +123,13 @@ 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)
@@ -146,17 +139,17 @@ class DebugClassLoader
try {
if ($this->isFinder && !isset($this->loaded[$class])) {
$this->loaded[$class] = true;
if (!$file = $this->classLoader[0]->findFile($class) ?: false) {
// no-op
} elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) {
include $file;
if ($file = $this->classLoader[0]->findFile($class) ?: false) {
$wasCached = \function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file);
return;
} elseif (false === include $file) {
return;
require $file;
if ($wasCached) {
return;
}
}
} else {
\call_user_func($this->classLoader, $class);
call_user_func($this->classLoader, $class);
$file = false;
}
} finally {
@@ -168,7 +161,7 @@ class DebugClassLoader
private function checkClass($class, $file = null)
{
$exists = null === $file || class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
$exists = null === $file || \class_exists($class, false) || \interface_exists($class, false) || \trait_exists($class, false);
if (null !== $file && $class && '\\' === $class[0]) {
$class = substr($class, 1);
@@ -186,244 +179,200 @@ class DebugClassLoader
}
$name = $refl->getName();
if ($name !== $class && 0 === strcasecmp($name, $class)) {
if ($name !== $class && 0 === \strcasecmp($name, $class)) {
throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: "%s" vs "%s".', $class, $name));
}
$deprecations = $this->checkAnnotations($refl, $name);
if (isset(self::$php7Reserved[strtolower($refl->getShortName())])) {
$deprecations[] = sprintf('The "%s" class uses the reserved name "%s", it will break on PHP 7 and higher', $name, $refl->getShortName());
}
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 and @internal annotations for methods
self::$finalMethods[$class] = [];
self::$internalMethods[$class] = [];
foreach ($parentAndOwnInterfaces as $use) {
foreach (['finalMethods', 'internalMethods'] as $property) {
if (isset(self::${$property}[$use])) {
self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use];
}
}
}
foreach ($refl->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $method) {
if ($method->class !== $class) {
continue;
}
if ($parent && isset(self::$finalMethods[$parent][$method->name])) {
list($declaringClass, $message) = self::$finalMethods[$parent][$method->name];
$deprecations[] = sprintf('The "%s::%s()" method is considered final%s. It may change without further notice as of its next major version. You should not extend it from "%s".', $declaringClass, $method->name, $message, $class);
}
if (isset(self::$internalMethods[$class][$method->name])) {
list($declaringClass, $message) = self::$internalMethods[$class][$method->name];
if (strncmp($ns, $declaringClass, $len)) {
$deprecations[] = sprintf('The "%s::%s()" method is considered internal%s. It may change without further notice. You should not extend it from "%s".', $declaringClass, $method->name, $message, $class);
}
}
// Detect method annotations
if (false === $doc = $method->getDocComment()) {
continue;
}
foreach (['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];
}
}
}
return $deprecations;
}
/**
* @param string $file
* @param string $class
*
* @return array|null
*/
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 null;
}
$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)];
}
return null;
}
/**
* `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];
// Don't trigger deprecations for classes in the same vendor
if (2 > $len = 1 + (\strpos($name, '\\') ?: \strpos($name, '_'))) {
$len = 0;
$ns = '';
} 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] = [$dir, []];
self::$darwinCache[$dir] = &self::$darwinCache[$k];
while ('/' !== $dir[--$i]) {
}
$k = substr($k, 0, ++$i);
$dir = substr($dir, 0, $i--);
}
$ns = \substr($name, 0, $len);
}
}
$dirFiles = self::$darwinCache[$kDir][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;
// 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);
}
}
}
self::$darwinCache[$kDir][1] = $dirFiles;
}
return $real.$dirFiles[$kFile];
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));
}
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)));
}
}
}
}
/**

View File

@@ -11,17 +11,16 @@
namespace Symfony\Component\Debug;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Symfony\Component\Debug\Exception\ContextErrorException;
use Psr\Log\LoggerInterface;
use Symfony\Component\Debug\Exception\FatalErrorException;
use Symfony\Component\Debug\Exception\FatalThrowableError;
use Symfony\Component\Debug\Exception\OutOfMemoryException;
use Symfony\Component\Debug\Exception\SilencedErrorContext;
use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
use Symfony\Component\Debug\FatalErrorHandler\FatalErrorHandlerInterface;
use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler;
use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
use Symfony\Component\Debug\FatalErrorHandler\FatalErrorHandlerInterface;
/**
* A generic ErrorHandler for the PHP engine.
@@ -48,7 +47,7 @@ use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
*/
class ErrorHandler
{
private $levels = [
private $levels = array(
E_DEPRECATED => 'Deprecated',
E_USER_DEPRECATED => 'User Deprecated',
E_NOTICE => 'Notice',
@@ -64,25 +63,25 @@ class ErrorHandler
E_PARSE => 'Parse Error',
E_ERROR => 'Error',
E_CORE_ERROR => 'Core Error',
];
);
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 $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 $thrownErrors = 0x1FFF; // E_ALL - E_DEPRECATED - E_USER_DEPRECATED
private $scopedErrors = 0x1FFF; // E_ALL - E_DEPRECATED - E_USER_DEPRECATED
@@ -97,10 +96,8 @@ class ErrorHandler
private $bootstrappingLogger;
private static $reservedMemory;
private static $stackedErrors = [];
private static $stackedErrorLevels = [];
private static $toStringException = null;
private static $silencedErrorCache = [];
private static $silencedErrorCache = array();
private static $silencedErrorCount = 0;
private static $exitCode = 0;
@@ -123,29 +120,29 @@ class ErrorHandler
$handler = new static();
}
if (null === $prev = set_error_handler([$handler, 'handleError'])) {
if (null === $prev = set_error_handler(array($handler, 'handleError'))) {
restore_error_handler();
// Specifying the error types earlier would expose us to https://bugs.php.net/63206
set_error_handler([$handler, 'handleError'], $handler->thrownErrors | $handler->loggedErrors);
set_error_handler(array($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([$handler, 'handleException'])) && $prev[0] instanceof self) {
if (is_array($prev = set_exception_handler(array($handler, 'handleException'))) && $prev[0] instanceof self) {
restore_exception_handler();
if (!$handlerIsRegistered) {
$handler = $prev[0];
} elseif ($handler !== $prev[0] && $replace) {
set_exception_handler([$handler, 'handleException']);
set_exception_handler(array($handler, 'handleException'));
$p = $prev[0]->setExceptionHandler(null);
$handler->setExceptionHandler($p);
$prev[0]->setExceptionHandler($p);
@@ -178,12 +175,12 @@ class ErrorHandler
*/
public function setDefaultLogger(LoggerInterface $logger, $levels = E_ALL, $replace = false)
{
$loggers = [];
$loggers = array();
if (\is_array($levels)) {
if (is_array($levels)) {
foreach ($levels as $type => $logLevel) {
if (empty($this->loggers[$type][0]) || $replace || $this->loggers[$type][0] === $this->bootstrappingLogger) {
$loggers[$type] = [$logger, $logLevel];
$loggers[$type] = array($logger, $logLevel);
}
}
} else {
@@ -214,15 +211,15 @@ class ErrorHandler
{
$prevLogged = $this->loggedErrors;
$prev = $this->loggers;
$flush = [];
$flush = array();
foreach ($loggers as $type => $log) {
if (!isset($prev[$type])) {
throw new \InvalidArgumentException('Unknown error type: '.$type);
}
if (!\is_array($log)) {
$log = [$log];
} elseif (!\array_key_exists(0, $log)) {
if (!is_array($log)) {
$log = array($log);
} elseif (!array_key_exists(0, $log)) {
throw new \InvalidArgumentException('No logger provided');
}
if (null === $log[0]) {
@@ -353,14 +350,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([$this, 'handleError'], $this->thrownErrors | $this->loggedErrors);
set_error_handler(array($this, 'handleError'), $this->thrownErrors | $this->loggedErrors);
} else {
set_error_handler([$this, 'handleError']);
set_error_handler(array($this, 'handleError'));
}
}
}
@@ -382,10 +379,6 @@ class ErrorHandler
*/
public function handleError($type, $message, $file, $line)
{
if (\PHP_VERSION_ID >= 70300 && E_WARNING === $type && '"' === $message[0] && false !== strpos($message, '" targeting switch is equivalent to "break')) {
$type = E_DEPRECATED;
}
// Level is the current error reporting level to manage silent error.
$level = error_reporting();
$silenced = 0 === ($level & $type);
@@ -400,12 +393,10 @@ class ErrorHandler
}
$scope = $this->scopedErrors & $type;
if (4 < $numArgs = \func_num_args()) {
$context = $scope ? (func_get_arg(4) ?: []) : [];
$backtrace = 5 < $numArgs ? func_get_arg(5) : null; // defined on HHVM
if (4 < $numArgs = func_num_args()) {
$context = $scope ? (func_get_arg(4) ?: array()) : array();
} else {
$context = [];
$backtrace = null;
$context = array();
}
if (isset($context['GLOBALS']) && $scope) {
@@ -414,15 +405,6 @@ class ErrorHandler
$context = $e;
}
if (null !== $backtrace && $type & E_ERROR) {
// E_ERROR fatal errors are triggered on HHVM when
// hhvm.error_handling.call_user_handler_on_fatals=1
// which is the way to get their backtrace.
$this->handleFatalError(compact('type', 'message', 'file', 'line', 'backtrace'));
return true;
}
$logMessage = $this->levels[$type].': '.$message;
if (null !== self::$toStringException) {
@@ -430,46 +412,43 @@ class ErrorHandler
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) : [];
$lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3), $type, $file, $line, false) : array();
$errorAsException = new SilencedErrorContext($type, $file, $line, $lightTrace);
} elseif (isset(self::$silencedErrorCache[$id][$message])) {
$lightTrace = null;
$errorAsException = self::$silencedErrorCache[$id][$message];
++$errorAsException->count;
} else {
$lightTrace = [];
$lightTrace = array();
$errorAsException = null;
}
if (100 < ++self::$silencedErrorCount) {
self::$silencedErrorCache = $lightTrace = [];
self::$silencedErrorCache = $lightTrace = array();
self::$silencedErrorCount = 1;
}
if ($errorAsException) {
self::$silencedErrorCache[$id][$message] = $errorAsException;
}
if (null === $lightTrace) {
return true;
return;
}
} else {
if ($scope) {
$errorAsException = new ContextErrorException($logMessage, 0, $type, $file, $line, $context);
} else {
$errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line);
}
$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 = $backtrace ?: $errorAsException->getTrace();
$backtrace = $errorAsException->getTrace();
$lightTrace = $this->cleanTrace($backtrace, $type, $file, $line, $throw);
$this->traceReflector->setValue($errorAsException, $lightTrace);
} else {
$this->traceReflector->setValue($errorAsException, []);
$this->traceReflector->setValue($errorAsException, array());
$backtrace = array();
}
}
if ($throw) {
if (\PHP_VERSION_ID < 70400 && E_USER_ERROR & $type) {
if (E_USER_ERROR & $type) {
for ($i = 1; isset($backtrace[$i]); ++$i) {
if (isset($backtrace[$i]['function'], $backtrace[$i]['type'], $backtrace[$i - 1]['function'])
&& '__toString' === $backtrace[$i]['function']
@@ -478,32 +457,25 @@ class ErrorHandler
&& ('trigger_error' === $backtrace[$i - 1]['function'] || 'user_error' === $backtrace[$i - 1]['function'])
) {
// Here, we know trigger_error() has been called from __toString().
// HHVM is fine with throwing from __toString() but PHP triggers a fatal error instead.
// PHP triggers a fatal error when throwing from __toString().
// A small convention allows working around the limitation:
// given a caught $e exception in __toString(), quitting the method with
// `return trigger_error($e, E_USER_ERROR);` allows this error handler
// to make $e get through the __toString() barrier.
foreach ($context as $e) {
if (($e instanceof \Exception || $e instanceof \Throwable) && $e->__toString() === $message) {
if (1 === $i) {
// On HHVM
$errorAsException = $e;
break;
}
if ($e instanceof \Throwable && $e->__toString() === $message) {
self::$toStringException = $e;
return true;
}
}
if (1 < $i) {
// On PHP (not on HHVM), display the original error message instead of the default one.
$this->handleException($errorAsException);
// Display the original error message instead of the default one.
$this->handleException($errorAsException);
// Stop the process by giving back the error to the native handler.
return false;
}
// Stop the process by giving back the error to the native handler.
return false;
}
}
}
@@ -513,29 +485,13 @@ class ErrorHandler
if ($this->isRecursive) {
$log = 0;
} elseif (self::$stackedErrorLevels) {
self::$stackedErrors[] = [
$this->loggers[$type][0],
($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG,
$logMessage,
$errorAsException ? ['exception' => $errorAsException] : [],
];
} 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 ? ['exception' => $errorAsException] : []);
$this->loggers[$type][0]->log($level, $logMessage, $errorAsException ? array('exception' => $errorAsException) : array());
} finally {
$this->isRecursive = false;
if (!\defined('HHVM_VERSION')) {
set_error_handler($currentErrorHandler);
}
}
}
@@ -564,12 +520,12 @@ class ErrorHandler
if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
if ($exception instanceof FatalErrorException) {
if ($exception instanceof FatalThrowableError) {
$error = [
$error = array(
'type' => $type,
'message' => $message = $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
];
);
} else {
$message = 'Fatal '.$exception->getMessage();
}
@@ -581,8 +537,7 @@ class ErrorHandler
}
if ($this->loggedErrors & $type) {
try {
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, ['exception' => $exception]);
} catch (\Exception $handlerException) {
$this->loggers[$type][0]->log($this->loggers[$type][1], $message, array('exception' => $exception));
} catch (\Throwable $handlerException) {
}
}
@@ -598,12 +553,9 @@ class ErrorHandler
$this->exceptionHandler = null;
try {
if (null !== $exceptionHandler) {
$exceptionHandler($exception);
return;
return \call_user_func($exceptionHandler, $exception);
}
$handlerException = $handlerException ?: $exception;
} catch (\Exception $handlerException) {
} catch (\Throwable $handlerException) {
}
if ($exception === $handlerException) {
@@ -627,11 +579,11 @@ class ErrorHandler
}
$handler = self::$reservedMemory = null;
$handlers = [];
$handlers = array();
$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();
@@ -658,22 +610,12 @@ class ErrorHandler
$handler[0]->setExceptionHandler($h);
}
$handler = $handler[0];
$handlers = [];
$handlers = array();
if ($exit = null === $error) {
$error = error_get_last();
}
try {
while (self::$stackedErrorLevels) {
static::unstackErrors();
}
} catch (\Exception $exception) {
// Handled below
} catch (\Throwable $exception) {
// Handled below
}
if ($error && $error['type'] &= E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR) {
// Let's not throw anymore but keep logging
$handler->throwAt(0, true);
@@ -684,10 +626,12 @@ class ErrorHandler
} else {
$exception = new FatalErrorException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, true, $trace);
}
} else {
$exception = null;
}
try {
if (isset($exception)) {
if (null !== $exception) {
self::$exitCode = 255;
$handler->handleException($exception, $error);
}
@@ -701,55 +645,6 @@ class ErrorHandler
}
}
/**
* Configures the error handler for delayed handling.
* Ensures also that non-catchable fatal errors are never silenced.
*
* As shown by http://bugs.php.net/42098 and http://bugs.php.net/60724
* PHP has a compile stage where it behaves unusually. To workaround it,
* we plug an error handler that only stacks errors for later.
*
* The most important feature of this is to prevent
* autoloading until unstackErrors() is called.
*
* @deprecated since version 3.4, to be removed in 4.0.
*/
public static function stackErrors()
{
@trigger_error('Support for stacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
self::$stackedErrorLevels[] = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
}
/**
* Unstacks stacked errors and forwards to the logger.
*
* @deprecated since version 3.4, to be removed in 4.0.
*/
public static function unstackErrors()
{
@trigger_error('Support for unstacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
$level = array_pop(self::$stackedErrorLevels);
if (null !== $level) {
$errorReportingLevel = error_reporting($level);
if ($errorReportingLevel !== ($level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
// If the user changed the error level, do not overwrite it
error_reporting($errorReportingLevel);
}
}
if (empty(self::$stackedErrorLevels)) {
$errors = self::$stackedErrors;
self::$stackedErrors = [];
foreach ($errors as $error) {
$error[0]->log($error[1], $error[2], $error[3]);
}
}
}
/**
* Gets the fatal error handlers.
*
@@ -759,11 +654,11 @@ class ErrorHandler
*/
protected function getFatalErrorHandlers()
{
return [
return array(
new UndefinedFunctionFatalErrorHandler(),
new UndefinedMethodFatalErrorHandler(),
new ClassNotFoundFatalErrorHandler(),
];
);
}
private function cleanTrace($backtrace, $type, $file, $line, $throw)
@@ -772,7 +667,7 @@ class ErrorHandler
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;
}
}

View File

@@ -18,7 +18,7 @@ namespace Symfony\Component\Debug\Exception;
*/
class ClassNotFoundException extends FatalErrorException
{
public function __construct($message, \ErrorException $previous)
public function __construct(string $message, \ErrorException $previous)
{
parent::__construct(
$message,
@@ -26,9 +26,6 @@ class ClassNotFoundException extends FatalErrorException
$previous->getSeverity(),
$previous->getFile(),
$previous->getLine(),
null,
true,
null,
$previous->getPrevious()
);
$this->setTrace($previous->getTrace());

View File

@@ -1,40 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Debug\Exception;
/**
* Error Exception with Variable Context.
*
* @author Christian Sciberras <uuf6429@gmail.com>
*
* @deprecated since version 3.3. Instead, \ErrorException will be used directly in 4.0.
*/
class ContextErrorException extends \ErrorException
{
private $context = [];
public function __construct($message, $code, $severity, $filename, $lineno, $context = [])
{
parent::__construct($message, $code, $severity, $filename, $lineno);
$this->context = $context;
}
/**
* @return array Array of variables that existed when the exception occurred
*/
public function getContext()
{
@trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED);
return $this->context;
}
}

View File

@@ -18,9 +18,9 @@ namespace Symfony\Component\Debug\Exception;
*/
class FatalErrorException extends \ErrorException
{
public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true, array $trace = null, $previous = null)
public function __construct(string $message, int $code, int $severity, string $filename, int $lineno, int $traceOffset = null, bool $traceArgs = true, array $trace = null)
{
parent::__construct($message, $code, $severity, $filename, $lineno, $previous);
parent::__construct($message, $code, $severity, $filename, $lineno);
if (null !== $trace) {
if (!$traceArgs) {
@@ -31,7 +31,7 @@ class FatalErrorException extends \ErrorException
$this->setTrace($trace);
} elseif (null !== $traceOffset) {
if (\function_exists('xdebug_get_function_stack')) {
if (function_exists('xdebug_get_function_stack')) {
$trace = xdebug_get_function_stack();
if (0 < $traceOffset) {
array_splice($trace, -$traceOffset);
@@ -60,13 +60,8 @@ class FatalErrorException extends \ErrorException
unset($frame);
$trace = array_reverse($trace);
} elseif (\function_exists('symfony_debug_backtrace')) {
$trace = symfony_debug_backtrace();
if (0 < $traceOffset) {
array_splice($trace, 0, $traceOffset);
}
} else {
$trace = [];
$trace = array();
}
$this->setTrace($trace);

View File

@@ -33,7 +33,7 @@ class FlattenException
private $file;
private $line;
public static function create(\Exception $exception, $statusCode = null, array $headers = [])
public static function create(\Exception $exception, $statusCode = null, array $headers = array())
{
$e = new static();
$e->setMessage($exception->getMessage());
@@ -53,7 +53,7 @@ class FlattenException
$e->setStatusCode($statusCode);
$e->setHeaders($headers);
$e->setTraceFromException($exception);
$e->setClass(\get_class($exception));
$e->setClass(get_class($exception));
$e->setFile($exception->getFile());
$e->setLine($exception->getLine());
@@ -70,13 +70,13 @@ class FlattenException
public function toArray()
{
$exceptions = [];
foreach (array_merge([$this], $this->getAllPrevious()) as $exception) {
$exceptions[] = [
$exceptions = array();
foreach (array_merge(array($this), $this->getAllPrevious()) as $exception) {
$exceptions[] = array(
'message' => $exception->getMessage(),
'class' => $exception->getClass(),
'trace' => $exception->getTrace(),
];
);
}
return $exceptions;
@@ -164,7 +164,7 @@ class FlattenException
public function getAllPrevious()
{
$exceptions = [];
$exceptions = array();
$e = $this;
while ($e = $e->getPrevious()) {
$exceptions[] = $e;
@@ -185,8 +185,8 @@ class FlattenException
public function setTrace($trace, $file, $line)
{
$this->trace = [];
$this->trace[] = [
$this->trace = array();
$this->trace[] = array(
'namespace' => '',
'short_class' => '',
'class' => '',
@@ -194,8 +194,8 @@ class FlattenException
'function' => '',
'file' => $file,
'line' => $line,
'args' => [],
];
'args' => array(),
);
foreach ($trace as $entry) {
$class = '';
$namespace = '';
@@ -205,7 +205,7 @@ class FlattenException
$namespace = implode('\\', $parts);
}
$this->trace[] = [
$this->trace[] = array(
'namespace' => $namespace,
'short_class' => $class,
'class' => isset($entry['class']) ? $entry['class'] : '',
@@ -213,41 +213,41 @@ 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']) : [],
];
'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : array(),
);
}
}
private function flattenArgs($args, $level = 0, &$count = 0)
{
$result = [];
$result = array();
foreach ($args as $key => $value) {
if (++$count > 1e4) {
return ['array', '*SKIPPED over 10000 entries*'];
return array('array', '*SKIPPED over 10000 entries*');
}
if ($value instanceof \__PHP_Incomplete_Class) {
// is_object() returns false on PHP<=7.1
$result[$key] = ['incomplete-object', $this->getClassNameFromIncomplete($value)];
} elseif (\is_object($value)) {
$result[$key] = ['object', \get_class($value)];
} elseif (\is_array($value)) {
$result[$key] = array('incomplete-object', $this->getClassNameFromIncomplete($value));
} elseif (is_object($value)) {
$result[$key] = array('object', get_class($value));
} elseif (is_array($value)) {
if ($level > 10) {
$result[$key] = ['array', '*DEEP NESTED ARRAY*'];
$result[$key] = array('array', '*DEEP NESTED ARRAY*');
} else {
$result[$key] = ['array', $this->flattenArgs($value, $level + 1, $count)];
$result[$key] = array('array', $this->flattenArgs($value, $level + 1, $count));
}
} elseif (null === $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)];
$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));
} else {
$result[$key] = ['string', (string) $value];
$result[$key] = array('string', (string) $value);
}
}

View File

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

View File

@@ -18,7 +18,7 @@ namespace Symfony\Component\Debug\Exception;
*/
class UndefinedFunctionException extends FatalErrorException
{
public function __construct($message, \ErrorException $previous)
public function __construct(string $message, \ErrorException $previous)
{
parent::__construct(
$message,
@@ -26,9 +26,6 @@ class UndefinedFunctionException extends FatalErrorException
$previous->getSeverity(),
$previous->getFile(),
$previous->getLine(),
null,
true,
null,
$previous->getPrevious()
);
$this->setTrace($previous->getTrace());

View File

@@ -18,7 +18,7 @@ namespace Symfony\Component\Debug\Exception;
*/
class UndefinedMethodException extends FatalErrorException
{
public function __construct($message, \ErrorException $previous)
public function __construct(string $message, \ErrorException $previous)
{
parent::__construct(
$message,
@@ -26,9 +26,6 @@ class UndefinedMethodException extends FatalErrorException
$previous->getSeverity(),
$previous->getFile(),
$previous->getLine(),
null,
true,
null,
$previous->getPrevious()
);
$this->setTrace($previous->getTrace());

File diff suppressed because one or more lines are too long

View File

@@ -11,11 +11,11 @@
namespace Symfony\Component\Debug\FatalErrorHandler;
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;
use Symfony\Component\Debug\DebugClassLoader;
use Composer\Autoload\ClassLoader as ComposerClassLoader;
use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader;
/**
* ErrorHandler for classes that do not exist.
@@ -29,20 +29,20 @@ 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 null;
return;
}
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
return null;
return;
}
foreach (['class', 'interface', 'trait'] as $typeName) {
foreach (array('class', 'interface', 'trait') as $typeName) {
$prefix = ucfirst($typeName).' \'';
$prefixLen = \strlen($prefix);
$prefixLen = strlen($prefix);
if (0 !== strpos($error['message'], $prefix)) {
continue;
}
@@ -71,8 +71,6 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
return new ClassNotFoundException($message, $exception);
}
return null;
}
/**
@@ -85,24 +83,24 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
*
* @return array An array of possible fully qualified class names
*/
private function getClassCandidates($class)
private function getClassCandidates(string $class): array
{
if (!\is_array($functions = spl_autoload_functions())) {
return [];
if (!is_array($functions = spl_autoload_functions())) {
return array();
}
// find Symfony and Composer autoloaders
$classes = [];
$classes = array();
foreach ($functions as $function) {
if (!\is_array($function)) {
if (!is_array($function)) {
continue;
}
// get class loaders wrapped by DebugClassLoader
if ($function[0] instanceof DebugClassLoader) {
$function = $function[0]->getClassLoader();
if (!\is_array($function)) {
if (!is_array($function)) {
continue;
}
}
@@ -126,20 +124,13 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
return array_unique($classes);
}
/**
* @param string $path
* @param string $class
* @param string $prefix
*
* @return array
*/
private function findClassInPath($path, $class, $prefix)
private function findClassInPath(string $path, string $class, string $prefix): array
{
if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
return [];
if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) {
return array();
}
$classes = [];
$classes = array();
$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)) {
@@ -150,18 +141,11 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
return $classes;
}
/**
* @param string $path
* @param string $file
* @param string $prefix
*
* @return string|null
*/
private function convertFileToClass($path, $file, $prefix)
private function convertFileToClass(string $path, string $file, string $prefix): ?string
{
$candidates = [
$candidates = array(
// namespaced class
$namespacedClass = str_replace([$path.\DIRECTORY_SEPARATOR, '.php', '/'], ['', '', '\\'], $file),
$namespacedClass = str_replace(array($path.DIRECTORY_SEPARATOR, '.php', '/'), array('', '', '\\'), $file),
// namespaced class (with target dir)
$prefix.$namespacedClass,
// namespaced class (with target dir and separator)
@@ -172,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); });
@@ -187,11 +171,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
}
}
try {
require_once $file;
} catch (\Throwable $e) {
return null;
}
require_once $file;
foreach ($candidates as $candidate) {
if ($this->classExists($candidate)) {
@@ -202,12 +182,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
return null;
}
/**
* @param string $class
*
* @return bool
*/
private function classExists($class)
private function classExists(string $class): bool
{
return class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
}

View File

@@ -11,8 +11,8 @@
namespace Symfony\Component\Debug\FatalErrorHandler;
use Symfony\Component\Debug\Exception\FatalErrorException;
use Symfony\Component\Debug\Exception\UndefinedFunctionException;
use Symfony\Component\Debug\Exception\FatalErrorException;
/**
* ErrorHandler for undefined functions.
@@ -26,21 +26,21 @@ 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 null;
return;
}
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
return null;
return;
}
$prefix = 'Call to undefined function ';
$prefixLen = \strlen($prefix);
$prefixLen = strlen($prefix);
if (0 !== strpos($error['message'], $prefix)) {
return null;
return;
}
$fullyQualifiedFunctionName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
@@ -53,7 +53,7 @@ class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface
$message = sprintf('Attempted to call function "%s" from the global namespace.', $functionName);
}
$candidates = [];
$candidates = array();
foreach (get_defined_functions() as $type => $definedFunctionNames) {
foreach ($definedFunctionNames as $definedFunctionName) {
if (false !== $namespaceSeparatorIndex = strrpos($definedFunctionName, '\\')) {

View File

@@ -28,7 +28,7 @@ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
{
preg_match('/^Call to undefined method (.*)::(.*)\(\)$/', $error['message'], $matches);
if (!$matches) {
return null;
return;
}
$className = $matches[1];
@@ -41,10 +41,10 @@ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
return new UndefinedMethodException($message, $exception);
}
$candidates = [];
$candidates = array();
foreach ($methods as $definedMethodName) {
$lev = levenshtein($methodName, $definedMethodName);
if ($lev <= \strlen($methodName) / 3 || false !== strpos($definedMethodName, $methodName)) {
if ($lev <= strlen($methodName) / 3 || false !== strpos($definedMethodName, $methodName)) {
$candidates[] = $definedMethodName;
}
}

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2019 Fabien Potencier
Copyright (c) 2004-2018 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,134 +0,0 @@
Symfony Debug Extension for PHP 5
=================================
This extension publishes several functions to help building powerful debugging tools.
It is compatible with PHP 5.3, 5.4, 5.5 and 5.6; with ZTS and non-ZTS modes.
It is not required thus not provided for PHP 7.
symfony_zval_info()
-------------------
- exposes zval_hash/refcounts, allowing e.g. efficient exploration of arbitrary structures in PHP,
- does work with references, preventing memory copying.
Its behavior is about the same as:
```php
<?php
function symfony_zval_info($key, $array, $options = 0)
{
// $options is currently not used, but could be in future version.
if (!array_key_exists($key, $array)) {
return null;
}
$info = [
'type' => gettype($array[$key]),
'zval_hash' => /* hashed memory address of $array[$key] */,
'zval_refcount' => /* internal zval refcount of $array[$key] */,
'zval_isref' => /* is_ref status of $array[$key] */,
];
switch ($info['type']) {
case 'object':
$info += [
'object_class' => get_class($array[$key]),
'object_refcount' => /* internal object refcount of $array[$key] */,
'object_hash' => spl_object_hash($array[$key]),
'object_handle' => /* internal object handle $array[$key] */,
];
break;
case 'resource':
$info += [
'resource_handle' => (int) $array[$key],
'resource_type' => get_resource_type($array[$key]),
'resource_refcount' => /* internal resource refcount of $array[$key] */,
];
break;
case 'array':
$info += [
'array_count' => count($array[$key]),
];
break;
case 'string':
$info += [
'strlen' => strlen($array[$key]),
];
break;
}
return $info;
}
```
symfony_debug_backtrace()
-------------------------
This function works like debug_backtrace(), except that it can fetch the full backtrace in case of fatal errors:
```php
function foo() { fatal(); }
function bar() { foo(); }
function sd() { var_dump(symfony_debug_backtrace()); }
register_shutdown_function('sd');
bar();
/* Will output
Fatal error: Call to undefined function fatal() in foo.php on line 42
array(3) {
[0]=>
array(2) {
["function"]=>
string(2) "sd"
["args"]=>
array(0) {
}
}
[1]=>
array(4) {
["file"]=>
string(7) "foo.php"
["line"]=>
int(1)
["function"]=>
string(3) "foo"
["args"]=>
array(0) {
}
}
[2]=>
array(4) {
["file"]=>
string(102) "foo.php"
["line"]=>
int(2)
["function"]=>
string(3) "bar"
["args"]=>
array(0) {
}
}
}
*/
```
Usage
-----
To enable the extension from source, run:
```
phpize
./configure
make
sudo make install
```

View File

@@ -1,63 +0,0 @@
dnl $Id$
dnl config.m4 for extension symfony_debug
dnl Comments in this file start with the string 'dnl'.
dnl Remove where necessary. This file will not work
dnl without editing.
dnl If your extension references something external, use with:
dnl PHP_ARG_WITH(symfony_debug, for symfony_debug support,
dnl Make sure that the comment is aligned:
dnl [ --with-symfony_debug Include symfony_debug support])
dnl Otherwise use enable:
PHP_ARG_ENABLE(symfony_debug, whether to enable symfony_debug support,
dnl Make sure that the comment is aligned:
[ --enable-symfony_debug Enable symfony_debug support])
if test "$PHP_SYMFONY_DEBUG" != "no"; then
dnl Write more examples of tests here...
dnl # --with-symfony_debug -> check with-path
dnl SEARCH_PATH="/usr/local /usr" # you might want to change this
dnl SEARCH_FOR="/include/symfony_debug.h" # you most likely want to change this
dnl if test -r $PHP_SYMFONY_DEBUG/$SEARCH_FOR; then # path given as parameter
dnl SYMFONY_DEBUG_DIR=$PHP_SYMFONY_DEBUG
dnl else # search default path list
dnl AC_MSG_CHECKING([for symfony_debug files in default path])
dnl for i in $SEARCH_PATH ; do
dnl if test -r $i/$SEARCH_FOR; then
dnl SYMFONY_DEBUG_DIR=$i
dnl AC_MSG_RESULT(found in $i)
dnl fi
dnl done
dnl fi
dnl
dnl if test -z "$SYMFONY_DEBUG_DIR"; then
dnl AC_MSG_RESULT([not found])
dnl AC_MSG_ERROR([Please reinstall the symfony_debug distribution])
dnl fi
dnl # --with-symfony_debug -> add include path
dnl PHP_ADD_INCLUDE($SYMFONY_DEBUG_DIR/include)
dnl # --with-symfony_debug -> check for lib and symbol presence
dnl LIBNAME=symfony_debug # you may want to change this
dnl LIBSYMBOL=symfony_debug # you most likely want to change this
dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
dnl [
dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $SYMFONY_DEBUG_DIR/lib, SYMFONY_DEBUG_SHARED_LIBADD)
dnl AC_DEFINE(HAVE_SYMFONY_DEBUGLIB,1,[ ])
dnl ],[
dnl AC_MSG_ERROR([wrong symfony_debug lib version or lib not found])
dnl ],[
dnl -L$SYMFONY_DEBUG_DIR/lib -lm
dnl ])
dnl
dnl PHP_SUBST(SYMFONY_DEBUG_SHARED_LIBADD)
PHP_NEW_EXTENSION(symfony_debug, symfony_debug.c, $ext_shared)
fi

View File

@@ -1,13 +0,0 @@
// $Id$
// vim:ft=javascript
// If your extension references something external, use ARG_WITH
// ARG_WITH("symfony_debug", "for symfony_debug support", "no");
// Otherwise, use ARG_ENABLE
// ARG_ENABLE("symfony_debug", "enable symfony_debug support", "no");
if (PHP_SYMFONY_DEBUG != "no") {
EXTENSION("symfony_debug", "symfony_debug.c");
}

View File

@@ -1,60 +0,0 @@
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#ifndef PHP_SYMFONY_DEBUG_H
#define PHP_SYMFONY_DEBUG_H
extern zend_module_entry symfony_debug_module_entry;
#define phpext_symfony_debug_ptr &symfony_debug_module_entry
#define PHP_SYMFONY_DEBUG_VERSION "2.7"
#ifdef PHP_WIN32
# define PHP_SYMFONY_DEBUG_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
# define PHP_SYMFONY_DEBUG_API __attribute__ ((visibility("default")))
#else
# define PHP_SYMFONY_DEBUG_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
ZEND_BEGIN_MODULE_GLOBALS(symfony_debug)
intptr_t req_rand_init;
void (*old_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);
zval *debug_bt;
ZEND_END_MODULE_GLOBALS(symfony_debug)
PHP_MINIT_FUNCTION(symfony_debug);
PHP_MSHUTDOWN_FUNCTION(symfony_debug);
PHP_RINIT_FUNCTION(symfony_debug);
PHP_RSHUTDOWN_FUNCTION(symfony_debug);
PHP_MINFO_FUNCTION(symfony_debug);
PHP_GINIT_FUNCTION(symfony_debug);
PHP_GSHUTDOWN_FUNCTION(symfony_debug);
PHP_FUNCTION(symfony_zval_info);
PHP_FUNCTION(symfony_debug_backtrace);
static char *_symfony_debug_memory_address_hash(void * TSRMLS_DC);
static const char *_symfony_debug_zval_type(zval *);
static const char* _symfony_debug_get_resource_type(long TSRMLS_DC);
static int _symfony_debug_get_resource_refcount(long TSRMLS_DC);
void symfony_debug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);
#ifdef ZTS
#define SYMFONY_DEBUG_G(v) TSRMG(symfony_debug_globals_id, zend_symfony_debug_globals *, v)
#else
#define SYMFONY_DEBUG_G(v) (symfony_debug_globals.v)
#endif
#endif /* PHP_SYMFONY_DEBUG_H */

View File

@@ -1,283 +0,0 @@
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#ifdef ZTS
#include "TSRM.h"
#endif
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_symfony_debug.h"
#include "ext/standard/php_rand.h"
#include "ext/standard/php_lcg.h"
#include "ext/spl/php_spl.h"
#include "Zend/zend_gc.h"
#include "Zend/zend_builtin_functions.h"
#include "Zend/zend_extensions.h" /* for ZEND_EXTENSION_API_NO */
#include "ext/standard/php_array.h"
#include "Zend/zend_interfaces.h"
#include "SAPI.h"
#define IS_PHP_53 ZEND_EXTENSION_API_NO == 220090626
ZEND_DECLARE_MODULE_GLOBALS(symfony_debug)
ZEND_BEGIN_ARG_INFO_EX(symfony_zval_arginfo, 0, 0, 2)
ZEND_ARG_INFO(0, key)
ZEND_ARG_ARRAY_INFO(0, array, 0)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
const zend_function_entry symfony_debug_functions[] = {
PHP_FE(symfony_zval_info, symfony_zval_arginfo)
PHP_FE(symfony_debug_backtrace, NULL)
PHP_FE_END
};
PHP_FUNCTION(symfony_debug_backtrace)
{
if (zend_parse_parameters_none() == FAILURE) {
return;
}
#if IS_PHP_53
zend_fetch_debug_backtrace(return_value, 1, 0 TSRMLS_CC);
#else
zend_fetch_debug_backtrace(return_value, 1, 0, 0 TSRMLS_CC);
#endif
if (!SYMFONY_DEBUG_G(debug_bt)) {
return;
}
php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(SYMFONY_DEBUG_G(debug_bt)), 0 TSRMLS_CC);
}
PHP_FUNCTION(symfony_zval_info)
{
zval *key = NULL, *arg = NULL;
zval **data = NULL;
HashTable *array = NULL;
long options = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zh|l", &key, &array, &options) == FAILURE) {
return;
}
switch (Z_TYPE_P(key)) {
case IS_STRING:
if (zend_symtable_find(array, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&data) == FAILURE) {
return;
}
break;
case IS_LONG:
if (zend_hash_index_find(array, Z_LVAL_P(key), (void **)&data)) {
return;
}
break;
}
arg = *data;
array_init(return_value);
add_assoc_string(return_value, "type", (char *)_symfony_debug_zval_type(arg), 1);
add_assoc_stringl(return_value, "zval_hash", _symfony_debug_memory_address_hash((void *)arg TSRMLS_CC), 16, 0);
add_assoc_long(return_value, "zval_refcount", Z_REFCOUNT_P(arg));
add_assoc_bool(return_value, "zval_isref", (zend_bool)Z_ISREF_P(arg));
if (Z_TYPE_P(arg) == IS_OBJECT) {
char hash[33] = {0};
php_spl_object_hash(arg, (char *)hash TSRMLS_CC);
add_assoc_stringl(return_value, "object_class", (char *)Z_OBJCE_P(arg)->name, Z_OBJCE_P(arg)->name_length, 1);
add_assoc_long(return_value, "object_refcount", EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(arg)].bucket.obj.refcount);
add_assoc_string(return_value, "object_hash", hash, 1);
add_assoc_long(return_value, "object_handle", Z_OBJ_HANDLE_P(arg));
} else if (Z_TYPE_P(arg) == IS_ARRAY) {
add_assoc_long(return_value, "array_count", zend_hash_num_elements(Z_ARRVAL_P(arg)));
} else if(Z_TYPE_P(arg) == IS_RESOURCE) {
add_assoc_long(return_value, "resource_handle", Z_LVAL_P(arg));
add_assoc_string(return_value, "resource_type", (char *)_symfony_debug_get_resource_type(Z_LVAL_P(arg) TSRMLS_CC), 1);
add_assoc_long(return_value, "resource_refcount", _symfony_debug_get_resource_refcount(Z_LVAL_P(arg) TSRMLS_CC));
} else if (Z_TYPE_P(arg) == IS_STRING) {
add_assoc_long(return_value, "strlen", Z_STRLEN_P(arg));
}
}
void symfony_debug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args)
{
TSRMLS_FETCH();
zval *retval;
switch (type) {
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_CORE_WARNING:
case E_COMPILE_ERROR:
case E_COMPILE_WARNING:
ALLOC_INIT_ZVAL(retval);
#if IS_PHP_53
zend_fetch_debug_backtrace(retval, 1, 0 TSRMLS_CC);
#else
zend_fetch_debug_backtrace(retval, 1, 0, 0 TSRMLS_CC);
#endif
SYMFONY_DEBUG_G(debug_bt) = retval;
}
SYMFONY_DEBUG_G(old_error_cb)(type, error_filename, error_lineno, format, args);
}
static const char* _symfony_debug_get_resource_type(long rsid TSRMLS_DC)
{
const char *res_type;
res_type = zend_rsrc_list_get_rsrc_type(rsid TSRMLS_CC);
if (!res_type) {
return "Unknown";
}
return res_type;
}
static int _symfony_debug_get_resource_refcount(long rsid TSRMLS_DC)
{
zend_rsrc_list_entry *le;
if (zend_hash_index_find(&EG(regular_list), rsid, (void **) &le)==SUCCESS) {
return le->refcount;
}
return 0;
}
static char *_symfony_debug_memory_address_hash(void *address TSRMLS_DC)
{
char *result = NULL;
intptr_t address_rand;
if (!SYMFONY_DEBUG_G(req_rand_init)) {
if (!BG(mt_rand_is_seeded)) {
php_mt_srand(GENERATE_SEED() TSRMLS_CC);
}
SYMFONY_DEBUG_G(req_rand_init) = (intptr_t)php_mt_rand(TSRMLS_C);
}
address_rand = (intptr_t)address ^ SYMFONY_DEBUG_G(req_rand_init);
spprintf(&result, 17, "%016zx", address_rand);
return result;
}
static const char *_symfony_debug_zval_type(zval *zv)
{
switch (Z_TYPE_P(zv)) {
case IS_NULL:
return "NULL";
break;
case IS_BOOL:
return "boolean";
break;
case IS_LONG:
return "integer";
break;
case IS_DOUBLE:
return "double";
break;
case IS_STRING:
return "string";
break;
case IS_ARRAY:
return "array";
break;
case IS_OBJECT:
return "object";
case IS_RESOURCE:
return "resource";
default:
return "unknown type";
}
}
zend_module_entry symfony_debug_module_entry = {
STANDARD_MODULE_HEADER,
"symfony_debug",
symfony_debug_functions,
PHP_MINIT(symfony_debug),
PHP_MSHUTDOWN(symfony_debug),
PHP_RINIT(symfony_debug),
PHP_RSHUTDOWN(symfony_debug),
PHP_MINFO(symfony_debug),
PHP_SYMFONY_DEBUG_VERSION,
PHP_MODULE_GLOBALS(symfony_debug),
PHP_GINIT(symfony_debug),
PHP_GSHUTDOWN(symfony_debug),
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
#ifdef COMPILE_DL_SYMFONY_DEBUG
ZEND_GET_MODULE(symfony_debug)
#endif
PHP_GINIT_FUNCTION(symfony_debug)
{
memset(symfony_debug_globals, 0 , sizeof(*symfony_debug_globals));
}
PHP_GSHUTDOWN_FUNCTION(symfony_debug)
{
}
PHP_MINIT_FUNCTION(symfony_debug)
{
SYMFONY_DEBUG_G(old_error_cb) = zend_error_cb;
zend_error_cb = symfony_debug_error_cb;
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(symfony_debug)
{
zend_error_cb = SYMFONY_DEBUG_G(old_error_cb);
return SUCCESS;
}
PHP_RINIT_FUNCTION(symfony_debug)
{
return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(symfony_debug)
{
return SUCCESS;
}
PHP_MINFO_FUNCTION(symfony_debug)
{
php_info_print_table_start();
php_info_print_table_header(2, "Symfony Debug support", "enabled");
php_info_print_table_header(2, "Symfony Debug version", PHP_SYMFONY_DEBUG_VERSION);
php_info_print_table_end();
}

View File

@@ -1,155 +0,0 @@
--TEST--
Test symfony_zval_info API
--SKIPIF--
<?php if (!extension_loaded('symfony_debug')) {
echo 'skip';
} ?>
--FILE--
<?php
$int = 42;
$float = 42.42;
$str = 'foobar';
$object = new StdClass();
$array = ['foo', 'bar'];
$resource = tmpfile();
$null = null;
$bool = true;
$anotherint = 42;
$refcount2 = &$anotherint;
$var = [
'int' => $int,
'float' => $float,
'str' => $str,
'object' => $object,
'array' => $array,
'resource' => $resource,
'null' => $null,
'bool' => $bool,
'refcount' => &$refcount2,
];
var_dump(symfony_zval_info('int', $var));
var_dump(symfony_zval_info('float', $var));
var_dump(symfony_zval_info('str', $var));
var_dump(symfony_zval_info('object', $var));
var_dump(symfony_zval_info('array', $var));
var_dump(symfony_zval_info('resource', $var));
var_dump(symfony_zval_info('null', $var));
var_dump(symfony_zval_info('bool', $var));
var_dump(symfony_zval_info('refcount', $var));
var_dump(symfony_zval_info('not-exist', $var));
?>
--EXPECTF--
array(4) {
["type"]=>
string(7) "integer"
["zval_hash"]=>
string(16) "%s"
["zval_refcount"]=>
int(2)
["zval_isref"]=>
bool(false)
}
array(4) {
["type"]=>
string(6) "double"
["zval_hash"]=>
string(16) "%s"
["zval_refcount"]=>
int(2)
["zval_isref"]=>
bool(false)
}
array(5) {
["type"]=>
string(6) "string"
["zval_hash"]=>
string(16) "%s"
["zval_refcount"]=>
int(2)
["zval_isref"]=>
bool(false)
["strlen"]=>
int(6)
}
array(8) {
["type"]=>
string(6) "object"
["zval_hash"]=>
string(16) "%s"
["zval_refcount"]=>
int(2)
["zval_isref"]=>
bool(false)
["object_class"]=>
string(8) "stdClass"
["object_refcount"]=>
int(1)
["object_hash"]=>
string(32) "%s"
["object_handle"]=>
int(%d)
}
array(5) {
["type"]=>
string(5) "array"
["zval_hash"]=>
string(16) "%s"
["zval_refcount"]=>
int(2)
["zval_isref"]=>
bool(false)
["array_count"]=>
int(2)
}
array(7) {
["type"]=>
string(8) "resource"
["zval_hash"]=>
string(16) "%s"
["zval_refcount"]=>
int(2)
["zval_isref"]=>
bool(false)
["resource_handle"]=>
int(%d)
["resource_type"]=>
string(6) "stream"
["resource_refcount"]=>
int(1)
}
array(4) {
["type"]=>
string(4) "NULL"
["zval_hash"]=>
string(16) "%s"
["zval_refcount"]=>
int(2)
["zval_isref"]=>
bool(false)
}
array(4) {
["type"]=>
string(7) "boolean"
["zval_hash"]=>
string(16) "%s"
["zval_refcount"]=>
int(2)
["zval_isref"]=>
bool(false)
}
array(4) {
["type"]=>
string(7) "integer"
["zval_hash"]=>
string(16) "%s"
["zval_refcount"]=>
int(3)
["zval_isref"]=>
bool(true)
}
NULL

View File

@@ -1,65 +0,0 @@
--TEST--
Test symfony_debug_backtrace in case of fatal error
--SKIPIF--
<?php if (!extension_loaded('symfony_debug')) {
echo 'skip';
} ?>
--FILE--
<?php
function bar()
{
foo();
}
function foo()
{
notexist();
}
function bt()
{
print_r(symfony_debug_backtrace());
}
register_shutdown_function('bt');
bar();
?>
--EXPECTF--
Fatal error: Call to undefined function notexist() in %s on line %d
Array
(
[0] => Array
(
[function] => bt
[args] => Array
(
)
)
[1] => Array
(
[file] => %s
[line] => %d
[function] => foo
[args] => Array
(
)
)
[2] => Array
(
[file] => %s
[line] => %d
[function] => bar
[args] => Array
(
)
)
)

View File

@@ -1,48 +0,0 @@
--TEST--
Test symfony_debug_backtrace in case of non fatal error
--SKIPIF--
<?php if (!extension_loaded('symfony_debug')) {
echo 'skip';
} ?>
--FILE--
<?php
function bar()
{
bt();
}
function bt()
{
print_r(symfony_debug_backtrace());
}
bar();
?>
--EXPECTF--
Array
(
[0] => Array
(
[file] => %s
[line] => %d
[function] => bt
[args] => Array
(
)
)
[1] => Array
(
[file] => %s
[line] => %d
[function] => bar
[args] => Array
(
)
)
)

View File

@@ -1,87 +0,0 @@
--TEST--
Test ErrorHandler in case of fatal error
--SKIPIF--
<?php if (!extension_loaded('symfony_debug')) {
echo 'skip';
} ?>
--FILE--
<?php
namespace Psr\Log;
class LogLevel
{
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
}
namespace Symfony\Component\Debug;
$dir = __DIR__.'/../../../';
require $dir.'ErrorHandler.php';
require $dir.'Exception/FatalErrorException.php';
require $dir.'Exception/UndefinedFunctionException.php';
require $dir.'FatalErrorHandler/FatalErrorHandlerInterface.php';
require $dir.'FatalErrorHandler/ClassNotFoundFatalErrorHandler.php';
require $dir.'FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php';
require $dir.'FatalErrorHandler/UndefinedMethodFatalErrorHandler.php';
function bar()
{
foo();
}
function foo()
{
notexist();
}
$handler = ErrorHandler::register();
$handler->setExceptionHandler('print_r');
if (\function_exists('xdebug_disable')) {
xdebug_disable();
}
bar();
?>
--EXPECTF--
Fatal error: Call to undefined function Symfony\Component\Debug\notexist() in %s on line %d
Symfony\Component\Debug\Exception\UndefinedFunctionException Object
(
[message:protected] => Attempted to call function "notexist" from namespace "Symfony\Component\Debug".
[string:Exception:private] =>
[code:protected] => 0
[file:protected] => %s
[line:protected] => %d
[trace:Exception:private] => Array
(
[0] => Array
(
%A [function] => Symfony\Component\Debug\foo
%A [args] => Array
(
)
)
[1] => Array
(
%A [function] => Symfony\Component\Debug\bar
%A [args] => Array
(
)
)
%A
)
[previous:Exception:private] =>
[severity:protected] => 1
)

View File

@@ -13,7 +13,6 @@ namespace Symfony\Component\Debug\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Debug\DebugClassLoader;
use Symfony\Component\Debug\ErrorHandler;
class DebugClassLoaderTest extends TestCase
{
@@ -28,14 +27,14 @@ class DebugClassLoaderTest extends TestCase
{
$this->errorReporting = error_reporting(E_ALL);
$this->loader = new ClassLoader();
spl_autoload_register([$this->loader, 'loadClass'], true, true);
spl_autoload_register(array($this->loader, 'loadClass'), true, true);
DebugClassLoader::enable();
}
protected function tearDown()
{
DebugClassLoader::disable();
spl_autoload_unregister([$this->loader, 'loadClass']);
spl_autoload_unregister(array($this->loader, 'loadClass'));
error_reporting($this->errorReporting);
}
@@ -45,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);
@@ -59,10 +58,12 @@ class DebugClassLoaderTest extends TestCase
$this->fail('DebugClassLoader did not register');
}
/**
* @expectedException \Exception
* @expectedExceptionMessage boo
*/
public function testThrowingClass()
{
$this->expectException('Exception');
$this->expectExceptionMessage('boo');
try {
class_exists(__NAMESPACE__.'\Fixtures\Throwing');
$this->fail('Exception expected');
@@ -74,80 +75,20 @@ class DebugClassLoaderTest extends TestCase
class_exists(__NAMESPACE__.'\Fixtures\Throwing');
}
public function testUnsilencing()
{
if (\PHP_VERSION_ID >= 70000) {
$this->markTestSkipped('PHP7 throws exceptions, unsilencing is not required anymore.');
}
if (\defined('HHVM_VERSION')) {
$this->markTestSkipped('HHVM is not handled in this test case.');
}
ob_start();
$this->iniSet('log_errors', 0);
$this->iniSet('display_errors', 1);
// See below: this will fail with parse error
// but this should not be @-silenced.
@class_exists(__NAMESPACE__.'\TestingUnsilencing', true);
$output = ob_get_clean();
$this->assertStringMatchesFormat('%aParse error%a', $output);
}
public function testStacking()
{
// the ContextErrorException must not be loaded to test the workaround
// for https://bugs.php.net/65322.
if (class_exists('Symfony\Component\Debug\Exception\ContextErrorException', false)) {
$this->markTestSkipped('The ContextErrorException class is already loaded.');
}
if (\defined('HHVM_VERSION')) {
$this->markTestSkipped('HHVM is not handled in this test case.');
}
ErrorHandler::register();
try {
// Trigger autoloading + E_STRICT at compile time
// which in turn triggers $errorHandler->handle()
// that again triggers autoloading for ContextErrorException.
// Error stacking works around the bug above and everything is fine.
eval('
namespace '.__NAMESPACE__.';
class ChildTestingStacking extends TestingStacking { function foo($bar) {} }
');
$this->fail('ContextErrorException expected');
} catch (\ErrorException $exception) {
// if an exception is thrown, the test passed
$this->assertStringStartsWith(__FILE__, $exception->getFile());
if (\PHP_VERSION_ID < 70000) {
$this->assertRegExp('/^Runtime Notice: Declaration/', $exception->getMessage());
$this->assertEquals(E_STRICT, $exception->getSeverity());
} else {
$this->assertRegExp('/^Warning: Declaration/', $exception->getMessage());
$this->assertEquals(E_WARNING, $exception->getSeverity());
}
} finally {
restore_error_handler();
restore_exception_handler();
}
}
/**
* @expectedException \RuntimeException
*/
public function testNameCaseMismatch()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Case mismatch between loaded and declared class names');
class_exists(__NAMESPACE__.'\TestingCaseMismatch', true);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Case mismatch between class and real file names
*/
public function testFileCaseMismatch()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Case mismatch between class and real file names');
if (!file_exists(__DIR__.'/Fixtures/CaseMismatch.php')) {
$this->markTestSkipped('Can only be run on case insensitive filesystems');
}
@@ -155,10 +96,11 @@ class DebugClassLoaderTest extends TestCase
class_exists(__NAMESPACE__.'\Fixtures\CaseMismatch', true);
}
/**
* @expectedException \RuntimeException
*/
public function testPsr4CaseMismatch()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Case mismatch between loaded and declared class names');
class_exists(__NAMESPACE__.'\Fixtures\Psr4CaseMismatch', true);
}
@@ -184,7 +126,7 @@ class DebugClassLoaderTest extends TestCase
{
set_error_handler(function () { return false; });
$e = error_reporting(0);
@trigger_error('', E_USER_DEPRECATED);
trigger_error('', E_USER_DEPRECATED);
class_exists('Test\\'.__NAMESPACE__.'\\'.$class, true);
@@ -194,20 +136,20 @@ class DebugClassLoaderTest extends TestCase
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$xError = [
$xError = array(
'type' => E_USER_DEPRECATED,
'message' => 'The "Test\Symfony\Component\Debug\Tests\\'.$class.'" class '.$type.' "Symfony\Component\Debug\Tests\Fixtures\\'.$super.'" that is deprecated but this is a test deprecation notice.',
];
);
$this->assertSame($xError, $lastError);
}
public function provideDeprecatedSuper()
{
return [
['DeprecatedInterfaceClass', 'DeprecatedInterface', 'implements'],
['DeprecatedParentClass', 'DeprecatedClass', 'extends'],
];
return array(
array('DeprecatedInterfaceClass', 'DeprecatedInterface', 'implements'),
array('DeprecatedParentClass', 'DeprecatedClass', 'extends'),
);
}
public function testInterfaceExtendsDeprecatedInterface()
@@ -224,10 +166,10 @@ class DebugClassLoaderTest extends TestCase
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$xError = [
$xError = array(
'type' => E_USER_NOTICE,
'message' => '',
];
);
$this->assertSame($xError, $lastError);
}
@@ -246,25 +188,21 @@ class DebugClassLoaderTest extends TestCase
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$xError = [
$xError = array(
'type' => E_USER_NOTICE,
'message' => '',
];
);
$this->assertSame($xError, $lastError);
}
public function testReservedForPhp7()
public function testExtendedFinalClass()
{
if (\PHP_VERSION_ID >= 70000) {
$this->markTestSkipped('PHP7 already prevents using reserved names.');
}
set_error_handler(function () { return false; });
$e = error_reporting(0);
trigger_error('', E_USER_NOTICE);
class_exists('Test\\'.__NAMESPACE__.'\\Float', true);
class_exists('Test\\'.__NAMESPACE__.'\\ExtendsFinalClass', true);
error_reporting($e);
restore_error_handler();
@@ -272,60 +210,34 @@ class DebugClassLoaderTest extends TestCase
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$xError = [
$xError = array(
'type' => E_USER_DEPRECATED,
'message' => 'The "Test\Symfony\Component\Debug\Tests\Float" class uses the reserved name "Float", it will break on PHP 7 and higher',
];
'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);
}
public function testExtendedFinalClass()
{
$deprecations = [];
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
$e = error_reporting(E_USER_DEPRECATED);
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();
$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()
{
$deprecations = [];
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
$e = error_reporting(E_USER_DEPRECATED);
set_error_handler(function () { return false; });
$e = error_reporting(0);
trigger_error('', E_USER_NOTICE);
class_exists(__NAMESPACE__.'\\Fixtures\\ExtendedFinalMethod', true);
error_reporting($e);
restore_error_handler();
$xError = [
'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" method is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".',
'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod2()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".',
];
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$this->assertSame($xError, $deprecations);
$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);
}
public function testExtendedDeprecatedMethodDoesntTriggerAnyNotice()
@@ -342,12 +254,12 @@ class DebugClassLoaderTest extends TestCase
$lastError = error_get_last();
unset($lastError['file'], $lastError['line']);
$this->assertSame(['type' => E_USER_NOTICE, 'message' => ''], $lastError);
$this->assertSame(array('type' => E_USER_NOTICE, 'message' => ''), $lastError);
}
public function testInternalsUse()
{
$deprecations = [];
$deprecations = array();
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
$e = error_reporting(E_USER_DEPRECATED);
@@ -356,31 +268,12 @@ class DebugClassLoaderTest extends TestCase
error_reporting($e);
restore_error_handler();
$this->assertSame($deprecations, [
$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".',
'The "Symfony\Component\Debug\Tests\Fixtures\InternalInterface" interface is considered internal. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternalsParent".',
'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass" class is considered internal since version 3.4. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternalsParent".',
'The "Symfony\Component\Debug\Tests\Fixtures\InternalTrait" trait is considered internal. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".',
'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass::internalMethod()" method is considered internal since version 3.4. It may change without further notice. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".',
]);
}
public function testUseTraitWithInternalMethod()
{
$deprecations = [];
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));
'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".',
));
}
}
@@ -392,12 +285,12 @@ class ClassLoader
public function getClassMap()
{
return [__NAMESPACE__.'\Fixtures\NotPSR0bis' => __DIR__.'/Fixtures/notPsr0Bis.php'];
return array(__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 --');
@@ -406,7 +299,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) {
@@ -421,9 +314,8 @@ class ClassLoader
eval('namespace Test\\'.__NAMESPACE__.'; class NonDeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\NonDeprecatedInterface {}');
} elseif ('Test\\'.__NAMESPACE__.'\Float' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; class Float {}');
} 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__.'\ExtendsFinalClass' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsFinalClass extends \\'.__NAMESPACE__.'\Fixtures\FinalClass {}');
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsAnnotatedClass' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsAnnotatedClass extends \\'.__NAMESPACE__.'\Fixtures\AnnotatedClass {
public function deprecatedMethod() { }
@@ -436,10 +328,6 @@ 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; }');
}
return null;
}
}

View File

@@ -13,12 +13,9 @@ 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.
@@ -41,13 +38,13 @@ class ErrorHandlerTest extends TestCase
$this->assertSame($handler, ErrorHandler::register($newHandler, false));
$h = set_error_handler('var_dump');
restore_error_handler();
$this->assertSame([$handler, 'handleError'], $h);
$this->assertSame(array($handler, 'handleError'), $h);
try {
$this->assertSame($newHandler, ErrorHandler::register($newHandler, true));
$h = set_error_handler('var_dump');
restore_error_handler();
$this->assertSame([$newHandler, 'handleError'], $h);
$this->assertSame(array($newHandler, 'handleError'), $h);
} catch (\Exception $e) {
}
@@ -70,19 +67,19 @@ class ErrorHandlerTest extends TestCase
public function testErrorGetLast()
{
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$handler = ErrorHandler::register();
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$handler->setDefaultLogger($logger);
$handler->screamAt(E_ALL);
try {
@trigger_error('Hello', E_USER_WARNING);
$expected = [
$expected = array(
'type' => E_USER_WARNING,
'message' => 'Hello',
'file' => __FILE__,
'line' => __LINE__ - 5,
];
);
$this->assertSame($expected, error_get_last());
} catch (\Exception $e) {
restore_error_handler();
@@ -143,30 +140,31 @@ class ErrorHandlerTest extends TestCase
public function testDefaultLogger()
{
try {
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$handler = ErrorHandler::register();
$handler->setDefaultLogger($logger, E_NOTICE);
$handler->setDefaultLogger($logger, [E_USER_NOTICE => LogLevel::CRITICAL]);
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$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([]));
$handler->setDefaultLogger($logger, E_NOTICE);
$handler->setDefaultLogger($logger, array(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()));
} finally {
restore_error_handler();
restore_exception_handler();
@@ -178,14 +176,14 @@ class ErrorHandlerTest extends TestCase
try {
$handler = ErrorHandler::register();
$handler->throwAt(0, true);
$this->assertFalse($handler->handleError(0, 'foo', 'foo.php', 12, []));
$this->assertFalse($handler->handleError(0, 'foo', 'foo.php', 12, array()));
restore_error_handler();
restore_exception_handler();
$handler = ErrorHandler::register();
$handler->throwAt(3, true);
$this->assertFalse($handler->handleError(4, 'foo', 'foo.php', 12, []));
$this->assertFalse($handler->handleError(4, 'foo', 'foo.php', 12, array()));
restore_error_handler();
restore_exception_handler();
@@ -193,7 +191,7 @@ class ErrorHandlerTest extends TestCase
$handler = ErrorHandler::register();
$handler->throwAt(3, true);
try {
$handler->handleError(4, 'foo', 'foo.php', 12, []);
$handler->handleError(4, 'foo', 'foo.php', 12, array());
} catch (\ErrorException $e) {
$this->assertSame('Parse Error: foo', $e->getMessage());
$this->assertSame(4, $e->getSeverity());
@@ -206,14 +204,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, []));
$this->assertFalse($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, array()));
restore_error_handler();
restore_exception_handler();
$handler = ErrorHandler::register();
$handler->throwAt(E_DEPRECATED, true);
$this->assertFalse($handler->handleError(E_DEPRECATED, 'foo', 'foo.php', 12, []));
$this->assertFalse($handler->handleError(E_DEPRECATED, 'foo', 'foo.php', 12, array()));
restore_error_handler();
restore_exception_handler();
@@ -233,12 +231,12 @@ class ErrorHandlerTest extends TestCase
$logger
->expects($this->once())
->method('log')
->willReturnCallback($warnArgCheck)
->will($this->returnCallback($warnArgCheck))
;
$handler = ErrorHandler::register();
$handler->setDefaultLogger($logger, E_USER_DEPRECATED);
$this->assertTrue($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, []));
$this->assertTrue($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, array()));
restore_error_handler();
restore_exception_handler();
@@ -261,7 +259,7 @@ class ErrorHandlerTest extends TestCase
$logger
->expects($this->once())
->method('log')
->willReturnCallback($logArgCheck)
->will($this->returnCallback($logArgCheck))
;
$handler = ErrorHandler::register();
@@ -283,10 +281,6 @@ class ErrorHandlerTest extends TestCase
public function testHandleUserError()
{
if (\PHP_VERSION_ID >= 70400) {
$this->markTestSkipped('PHP 7.4 allows __toString to throw exceptions');
}
try {
$handler = ErrorHandler::register();
$handler->throwAt(0, true);
@@ -321,27 +315,23 @@ class ErrorHandlerTest extends TestCase
$logger
->expects($this->once())
->method('log')
->willReturnCallback($logArgCheck)
->will($this->returnCallback($logArgCheck))
;
$handler = new ErrorHandler();
$handler->setDefaultLogger($logger);
@$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, []);
restore_error_handler();
@$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, array());
}
/**
* @group no-hhvm
*/
public function testHandleException()
{
try {
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$handler = ErrorHandler::register();
$exception = new \Exception('foo');
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$logArgCheck = function ($level, $message, $context) {
$this->assertSame('Uncaught Exception: foo', $message);
$this->assertArrayHasKey('exception', $context);
@@ -351,7 +341,7 @@ class ErrorHandlerTest extends TestCase
$logger
->expects($this->exactly(2))
->method('log')
->willReturnCallback($logArgCheck)
->will($this->returnCallback($logArgCheck))
;
$handler->setDefaultLogger($logger, E_ERROR);
@@ -374,64 +364,32 @@ class ErrorHandlerTest extends TestCase
}
}
/**
* @group legacy
*/
public function testErrorStacking()
{
try {
$handler = ErrorHandler::register();
$handler->screamAt(E_USER_WARNING);
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$logger
->expects($this->exactly(2))
->method('log')
->withConsecutive(
[$this->equalTo(LogLevel::WARNING), $this->equalTo('Dummy log')],
[$this->equalTo(LogLevel::DEBUG), $this->equalTo('User Warning: Silenced warning')]
)
;
$handler->setDefaultLogger($logger, [E_USER_WARNING => LogLevel::WARNING]);
ErrorHandler::stackErrors();
@trigger_error('Silenced warning', E_USER_WARNING);
$logger->log(LogLevel::WARNING, 'Dummy log');
ErrorHandler::unstackErrors();
} finally {
restore_error_handler();
restore_exception_handler();
}
}
public function testBootstrappingLogger()
{
$bootLogger = new BufferingLogger();
$handler = new ErrorHandler($bootLogger);
$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],
];
$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),
);
$this->assertSame($loggers, $handler->setLoggers([]));
$this->assertSame($loggers, $handler->setLoggers(array()));
$handler->handleError(E_DEPRECATED, 'Foo message', __FILE__, 123, []);
$handler->handleError(E_DEPRECATED, 'Foo message', __FILE__, 123, array());
$logs = $bootLogger->cleanLogs();
@@ -447,19 +405,16 @@ class ErrorHandlerTest extends TestCase
$this->assertSame(123, $exception->getLine());
$this->assertSame(E_DEPRECATED, $exception->getSeverity());
$bootLogger->log(LogLevel::WARNING, 'Foo message', ['exception' => $exception]);
$bootLogger->log(LogLevel::WARNING, 'Foo message', array('exception' => $exception));
$mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$mockLogger->expects($this->once())
->method('log')
->with(LogLevel::WARNING, 'Foo message', ['exception' => $exception]);
->with(LogLevel::WARNING, 'Foo message', array('exception' => $exception));
$handler->setLoggers([E_DEPRECATED => [$mockLogger, LogLevel::WARNING]]);
$handler->setLoggers(array(E_DEPRECATED => array($mockLogger, LogLevel::WARNING)));
}
/**
* @group no-hhvm
*/
public function testSettingLoggerWhenExceptionIsBuffered()
{
$bootLogger = new BufferingLogger();
@@ -470,7 +425,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', ['exception' => $exception]);
->with(LogLevel::CRITICAL, 'Uncaught Exception: Foo message', array('exception' => $exception));
$handler->setExceptionHandler(function () use ($handler, $mockLogger) {
$handler->setDefaultLogger($mockLogger);
@@ -479,21 +434,19 @@ class ErrorHandlerTest extends TestCase
$handler->handleException($exception);
}
/**
* @group no-hhvm
*/
public function testHandleFatalError()
{
try {
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$handler = ErrorHandler::register();
$error = [
$error = array(
'type' => E_PARSE,
'message' => 'foo',
'file' => 'bar',
'line' => 123,
];
);
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$logArgCheck = function ($level, $message, $context) {
$this->assertEquals('Fatal Parse Error: foo', $message);
@@ -504,7 +457,7 @@ class ErrorHandlerTest extends TestCase
$logger
->expects($this->once())
->method('log')
->willReturnCallback($logArgCheck)
->will($this->returnCallback($logArgCheck))
;
$handler->setDefaultLogger($logger, E_PARSE);
@@ -521,67 +474,26 @@ class ErrorHandlerTest extends TestCase
}
}
/**
* @requires PHP 7
*/
public function testHandleErrorException()
{
$exception = new \Error("Class 'IReallyReallyDoNotExistAnywhereInTheRepositoryISwear' not found");
$exception = new \Error("Class 'Foo' not found");
$handler = new ErrorHandler();
$handler->setExceptionHandler(function () use (&$args) {
$args = \func_get_args();
$args = func_get_args();
});
$handler->handleException($exception);
$this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $args[0]);
$this->assertStringStartsWith("Attempted to load class \"IReallyReallyDoNotExistAnywhereInTheRepositoryISwear\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
$this->assertStringStartsWith("Attempted to load class \"Foo\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
}
/**
* @group no-hhvm
*/
public function testHandleFatalErrorOnHHVM()
{
try {
$handler = ErrorHandler::register();
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$logger
->expects($this->once())
->method('log')
->with(
$this->equalTo(LogLevel::CRITICAL),
$this->equalTo('Fatal Error: foo')
)
;
$handler->setDefaultLogger($logger, E_ERROR);
$error = [
'type' => E_ERROR + 0x1000000, // This error level is used by HHVM for fatal errors
'message' => 'foo',
'file' => 'bar',
'line' => 123,
'context' => [123],
'backtrace' => [456],
];
\call_user_func_array([$handler, 'handleError'], $error);
$handler->handleFatalError($error);
} finally {
restore_error_handler();
restore_exception_handler();
}
}
/**
* @group no-hhvm
* @expectedException \Exception
*/
public function testCustomExceptionHandler()
{
$this->expectException('Exception');
$handler = new ErrorHandler();
$handler->setExceptionHandler(function ($e) use ($handler) {
$handler->handleException($e);
@@ -589,58 +501,4 @@ 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

@@ -14,19 +14,19 @@ namespace Symfony\Component\Debug\Tests\Exception;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
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\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
@@ -54,7 +54,7 @@ class FlattenExceptionTest extends TestCase
$flattened = FlattenException::create(new ConflictHttpException());
$this->assertEquals('409', $flattened->getStatusCode());
$flattened = FlattenException::create(new MethodNotAllowedHttpException(['POST']));
$flattened = FlattenException::create(new MethodNotAllowedHttpException(array('POST')));
$this->assertEquals('405', $flattened->getStatusCode());
$flattened = FlattenException::create(new AccessDeniedHttpException());
@@ -89,23 +89,23 @@ class FlattenExceptionTest extends TestCase
public function testHeadersForHttpException()
{
$flattened = FlattenException::create(new MethodNotAllowedHttpException(['POST']));
$this->assertEquals(['Allow' => 'POST'], $flattened->getHeaders());
$flattened = FlattenException::create(new MethodNotAllowedHttpException(array('POST')));
$this->assertEquals(array('Allow' => 'POST'), $flattened->getHeaders());
$flattened = FlattenException::create(new UnauthorizedHttpException('Basic realm="My Realm"'));
$this->assertEquals(['WWW-Authenticate' => 'Basic realm="My Realm"'], $flattened->getHeaders());
$this->assertEquals(array('WWW-Authenticate' => 'Basic realm="My Realm"'), $flattened->getHeaders());
$flattened = FlattenException::create(new ServiceUnavailableHttpException('Fri, 31 Dec 1999 23:59:59 GMT'));
$this->assertEquals(['Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'], $flattened->getHeaders());
$this->assertEquals(array('Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'), $flattened->getHeaders());
$flattened = FlattenException::create(new ServiceUnavailableHttpException(120));
$this->assertEquals(['Retry-After' => 120], $flattened->getHeaders());
$this->assertEquals(array('Retry-After' => 120), $flattened->getHeaders());
$flattened = FlattenException::create(new TooManyRequestsHttpException('Fri, 31 Dec 1999 23:59:59 GMT'));
$this->assertEquals(['Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'], $flattened->getHeaders());
$this->assertEquals(array('Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'), $flattened->getHeaders());
$flattened = FlattenException::create(new TooManyRequestsHttpException(120));
$this->assertEquals(['Retry-After' => 120], $flattened->getHeaders());
$this->assertEquals(array('Retry-After' => 120), $flattened->getHeaders());
}
/**
@@ -135,12 +135,9 @@ class FlattenExceptionTest extends TestCase
$this->assertSame($flattened2, $flattened->getPrevious());
$this->assertSame([$flattened2], $flattened->getAllPrevious());
$this->assertSame(array($flattened2), $flattened->getAllPrevious());
}
/**
* @requires PHP 7.0
*/
public function testPreviousError()
{
$exception = new \Exception('test', 123, new \ParseError('Oh noes!', 42));
@@ -176,25 +173,25 @@ class FlattenExceptionTest extends TestCase
public function testToArray(\Exception $exception)
{
$flattened = FlattenException::create($exception);
$flattened->setTrace([], 'foo.php', 123);
$flattened->setTrace(array(), 'foo.php', 123);
$this->assertEquals([
[
$this->assertEquals(array(
array(
'message' => 'test',
'class' => 'Exception',
'trace' => [[
'trace' => array(array(
'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '', 'file' => 'foo.php', 'line' => 123,
'args' => [],
]],
],
], $flattened->toArray());
'args' => array(),
)),
),
), $flattened->toArray());
}
public function flattenDataProvider()
{
return [
[new \Exception('test', 123)],
];
return array(
array(new \Exception('test', 123)),
);
}
public function testArguments()
@@ -204,15 +201,15 @@ class FlattenExceptionTest extends TestCase
$incomplete = unserialize('O:14:"BogusTestClass":0:{}');
$exception = $this->createException([
(object) ['foo' => 1],
$exception = $this->createException(array(
(object) array('foo' => 1),
new NotFoundHttpException(),
$incomplete,
$dh,
$fh,
function () {},
[1, 2],
['foo' => 123],
array(1, 2),
array('foo' => 123),
null,
true,
false,
@@ -222,7 +219,7 @@ class FlattenExceptionTest extends TestCase
'',
INF,
NAN,
]);
));
$flattened = FlattenException::create($exception);
$trace = $flattened->getTrace();
@@ -233,46 +230,46 @@ class FlattenExceptionTest extends TestCase
fclose($fh);
$i = 0;
$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', \defined('HHVM_VERSION') ? 'Directory' : 'stream'], $array[$i++]);
$this->assertSame(['resource', 'stream'], $array[$i++]);
$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++]);
$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', [['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++]);
$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++]);
// assertEquals() does not like NAN values.
$this->assertEquals($array[$i][0], 'float');
$this->assertNan($array[$i][1]);
$this->assertTrue(is_nan($array[$i++][1]));
}
public function testRecursionInArguments()
{
$a = null;
$a = ['foo', [2, &$a]];
$a = array('foo', array(2, &$a));
$exception = $this->createException($a);
$flattened = FlattenException::create($exception);
$trace = $flattened->getTrace();
$this->assertStringContainsString('*DEEP NESTED ARRAY*', serialize($trace));
$this->assertContains('*DEEP NESTED ARRAY*', serialize($trace));
}
public function testTooBigArray()
{
$a = [];
$a = array();
for ($i = 0; $i < 20; ++$i) {
for ($j = 0; $j < 50; ++$j) {
for ($k = 0; $k < 10; ++$k) {
@@ -287,12 +284,12 @@ class FlattenExceptionTest extends TestCase
$flattened = FlattenException::create($exception);
$trace = $flattened->getTrace();
$this->assertSame($trace[1]['args'][0], ['array', ['array', '*SKIPPED over 10000 entries*']]);
$this->assertSame($trace[1]['args'][0], array('array', array('array', '*SKIPPED over 10000 entries*')));
$serializeTrace = serialize($trace);
$this->assertStringContainsString('*SKIPPED over 10000 entries*', $serializeTrace);
$this->assertStringNotContainsString('*value1*', $serializeTrace);
$this->assertContains('*SKIPPED over 10000 entries*', $serializeTrace);
$this->assertNotContains('*value1*', $serializeTrace);
}
private function createException($foo)

View File

@@ -12,10 +12,10 @@
namespace Symfony\Component\Debug\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Debug\Exception\OutOfMemoryException;
use Symfony\Component\Debug\ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\Debug\Exception\OutOfMemoryException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
require_once __DIR__.'/HeaderMock.php';
@@ -39,8 +39,8 @@ class ExceptionHandlerTest extends TestCase
$handler->sendPhpResponse(new \RuntimeException('Foo'));
$response = ob_get_clean();
$this->assertStringContainsString('Whoops, looks like something went wrong.', $response);
$this->assertStringNotContainsString('<div class="trace trace-as-html">', $response);
$this->assertContains('Whoops, looks like something went wrong.', $response);
$this->assertNotContains('<div class="trace trace-as-html">', $response);
$handler = new ExceptionHandler(true);
@@ -48,8 +48,8 @@ class ExceptionHandlerTest extends TestCase
$handler->sendPhpResponse(new \RuntimeException('Foo'));
$response = ob_get_clean();
$this->assertStringContainsString('Whoops, looks like something went wrong.', $response);
$this->assertStringContainsString('<div class="trace trace-as-html">', $response);
$this->assertContains('Whoops, looks like something went wrong.', $response);
$this->assertContains('<div class="trace trace-as-html">', $response);
}
public function testStatusCode()
@@ -60,12 +60,12 @@ class ExceptionHandlerTest extends TestCase
$handler->sendPhpResponse(new NotFoundHttpException('Foo'));
$response = ob_get_clean();
$this->assertStringContainsString('Sorry, the page you are looking for could not be found.', $response);
$this->assertContains('Sorry, the page you are looking for could not be found.', $response);
$expectedHeaders = [
['HTTP/1.0 404', true, null],
['Content-Type: text/html; charset=iso8859-1', true, null],
];
$expectedHeaders = array(
array('HTTP/1.0 404', true, null),
array('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(['POST']));
ob_get_clean();
$handler->sendPhpResponse(new MethodNotAllowedHttpException(array('POST')));
$response = ob_get_clean();
$expectedHeaders = [
['HTTP/1.0 405', true, null],
['Allow: POST', false, null],
['Content-Type: text/html; charset=iso8859-1', true, null],
];
$expectedHeaders = array(
array('HTTP/1.0 405', true, null),
array('Allow: POST', false, null),
array('Content-Type: text/html; charset=iso8859-1', true, null),
);
$this->assertSame($expectedHeaders, testHeader());
}
@@ -99,65 +99,35 @@ class ExceptionHandlerTest extends TestCase
public function testHandle()
{
$handler = new ExceptionHandler(true);
ob_start();
$exception = new \Exception('foo');
$handler->handle(new \Exception('foo'));
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(array('sendPhpResponse'))->getMock();
$handler
->expects($this->exactly(2))
->method('sendPhpResponse');
$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'foo');
}
$handler->handle($exception);
public function testHandleWithACustomHandlerThatOutputsSomething()
{
$handler = new ExceptionHandler(true);
ob_start();
$handler->setHandler(function () {
echo 'ccc';
$handler->setHandler(function ($e) use ($exception) {
$this->assertSame($exception, $e);
});
$handler->handle(new \Exception());
ob_end_flush(); // Necessary because of this PHP bug : https://bugs.php.net/76563
$this->assertSame('ccc', ob_get_clean());
}
public function testHandleWithACustomHandlerThatOutputsNothing()
{
$handler = new ExceptionHandler(true);
$handler->setHandler(function () {});
$handler->handle(new \Exception('ccc'));
$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'ccc');
}
public function testHandleWithACustomHandlerThatFails()
{
$handler = new ExceptionHandler(true);
$handler->setHandler(function () {
throw new \RuntimeException();
});
$handler->handle(new \Exception('ccc'));
$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'ccc');
$handler->handle($exception);
}
public function testHandleOutOfMemoryException()
{
$handler = new ExceptionHandler(true);
ob_start();
$handler->setHandler(function () {
$exception = new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__);
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(array('sendPhpResponse'))->getMock();
$handler
->expects($this->once())
->method('sendPhpResponse');
$handler->setHandler(function ($e) {
$this->fail('OutOfMemoryException should bypass the handler');
});
$handler->handle(new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__));
$this->assertThatTheExceptionWasOutput(ob_get_clean(), OutOfMemoryException::class, 'OutOfMemoryException', 'foo');
}
private function assertThatTheExceptionWasOutput($content, $expectedClass, $expectedTitle, $expectedMessage)
{
$this->assertStringContainsString(sprintf('<span class="exception_title"><abbr title="%s">%s</abbr></span>', $expectedClass, $expectedTitle), $content);
$this->assertStringContainsString(sprintf('<p class="break-long-words trace-message">%s</p>', $expectedMessage), $content);
$handler->handle($exception);
}
}

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;
}
}
@@ -61,7 +61,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
}
$this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $exception);
$this->assertRegExp($translatedMessage, $exception->getMessage());
$this->assertSame($translatedMessage, $exception->getMessage());
$this->assertSame($error['type'], $exception->getSeverity());
$this->assertSame($error['file'], $exception->getFile());
$this->assertSame($error['line'], $exception->getLine());
@@ -71,90 +71,86 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
{
$autoloader = new ComposerClassLoader();
$autoloader->add('Symfony\Component\Debug\Exception\\', realpath(__DIR__.'/../../Exception'));
$autoloader->add('Symfony_Component_Debug_Tests_Fixtures', realpath(__DIR__.'/../../Tests/Fixtures'));
$debugClassLoader = new DebugClassLoader([$autoloader, 'loadClass']);
$debugClassLoader = new DebugClassLoader(array($autoloader, 'loadClass'));
return [
[
[
return array(
array(
array(
'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\?$/",
],
[
[
),
"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\?$/",
],
[
[
),
"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\"\?$/",
[$debugClassLoader, 'loadClass'],
],
[
[
),
"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\"\?$/",
[$debugClassLoader, 'loadClass'],
],
[
[
),
"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\"\?$/",
[$debugClassLoader, 'loadClass'],
],
[
[
),
"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\"\?$/",
[$autoloader, 'loadClass'],
],
[
[
),
"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(
'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\"\?/",
[$debugClassLoader, 'loadClass'],
],
[
[
),
"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(
'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\?$/",
),
"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()
@@ -165,12 +161,12 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
require_once __DIR__.'/../FIXTURES2/REQUIREDTWICE.PHP';
$error = [
$error = array(
'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

@@ -26,7 +26,7 @@ class UndefinedFunctionFatalErrorHandlerTest extends TestCase
$exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line']));
$this->assertInstanceOf('Symfony\Component\Debug\Exception\UndefinedFunctionException', $exception);
// class names are case insensitive and PHP/HHVM do not return the same
// class names are case insensitive and PHP do not return the same
$this->assertSame(strtolower($translatedMessage), strtolower($exception->getMessage()));
$this->assertSame($error['type'], $exception->getSeverity());
$this->assertSame($error['file'], $exception->getFile());
@@ -35,44 +35,44 @@ class UndefinedFunctionFatalErrorHandlerTest extends TestCase
public function provideUndefinedFunctionData()
{
return [
[
[
return array(
array(
array(
'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 [
[
[
return array(
array(
array(
'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\"?",
],
[
[
'type' => 1,
'message' => 'Call to undefined method class@anonymous::test()',
'file' => '/home/possum/work/symfony/test.php',
'line' => 11,
],
),
array(
array(
'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

@@ -5,7 +5,7 @@ namespace Symfony\Component\Debug\Tests\Fixtures;
class AnnotatedClass
{
/**
* @deprecated since version 3.4.
* @deprecated
*/
public function deprecatedMethod()
{

View File

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

View File

@@ -1,22 +0,0 @@
<?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,8 +4,6 @@ namespace Symfony\Component\Debug\Tests\Fixtures;
class ExtendedFinalMethod extends FinalMethod
{
use FinalMethod2Trait;
/**
* {@inheritdoc}
*/

View File

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

View File

@@ -1,85 +0,0 @@
<?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

@@ -5,21 +5,12 @@ namespace Symfony\Component\Debug\Tests\Fixtures;
class FinalMethod
{
/**
* @final since version 3.3.
* @final
*/
public function finalMethod()
{
}
/**
* @final
*
* @return int
*/
public function finalMethod2()
{
}
public function anotherMethod()
{
}

View File

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

View File

@@ -3,7 +3,7 @@
namespace Symfony\Component\Debug\Tests\Fixtures;
/**
* @internal since version 3.4.
* @internal
*/
class InternalClass
{

View File

@@ -8,7 +8,7 @@ namespace Symfony\Component\Debug\Tests\Fixtures;
trait InternalTrait2
{
/**
* @internal since version 3.4
* @internal
*/
public function internalMethod()
{

View File

@@ -1,15 +0,0 @@
<?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

@@ -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 trigger_error($e, E_USER_ERROR);
return user_error($e, E_USER_ERROR);
}
}
}

View File

@@ -1,13 +0,0 @@
<?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 = [];
static $headers = array();
if (!$h = \func_get_args()) {
if (!$h = func_get_args()) {
$h = $headers;
$headers = [];
$headers = array();
return $h;
}
$headers[] = \func_get_args();
$headers[] = func_get_args();
}

View File

@@ -0,0 +1,24 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Debug\Tests;
use Symfony\Component\Debug\ExceptionHandler;
class MockExceptionHandler extends ExceptionHandler
{
public $e;
public function handle(\Exception $e)
{
$this->e = $e;
}
}

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';
@@ -23,5 +23,4 @@ class_exists(ExtendedFinalMethod::class);
?>
--EXPECTF--
The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" method is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".
The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod2()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".
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".

View File

@@ -1,7 +1,5 @@
--TEST--
Test catching fatal errors when handlers are nested
--INI--
display_errors=0
--FILE--
<?php
@@ -9,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';
@@ -26,6 +24,7 @@ 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".
@@ -39,7 +38,8 @@ Did you forget a "use" statement for another namespace?"
["line":protected]=>
int(%d)
["trace":"Exception":private]=>
array(%d) {%A}
array(0) {
}
["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 = [])
public function log($level, $message, array $context = array())
{
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([
var_dump(array(
$eHandler[0] === $xHandler[0] ? 'Error and exception handlers do match' : 'Error and exception handlers are different',
]);
));
$eHandler[0]->setExceptionHandler('print_r');

View File

@@ -16,14 +16,14 @@
}
],
"require": {
"php": "^5.5.9|>=7.0.8",
"php": "^7.1.3",
"psr/log": "~1.0"
},
"conflict": {
"symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "~2.8|~3.0|~4.0"
"symfony/http-kernel": "~3.4|~4.0"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Debug\\": "" },
@@ -34,7 +34,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
"dev-master": "4.0-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/5.2/phpunit.xsd"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"