feature #30323 [ErrorHandler] trigger deprecation in DebugClassLoader when child class misses a return type (fancyweb, nicolas-grekas)

This PR was merged into the 4.4 branch.

Discussion
----------

[ErrorHandler] trigger deprecation in DebugClassLoader when child class misses a return type

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

I wanted to push something to show the advancement and get feedback.

I pushed two versions : one with dedicated functions for code clarity (DebugClassLoader.php) and one withtout (DebugClassLoader___.php). It would be nice if some people with Blackfire could compare the performances.

So let's be clear, we are never gonna be able to cover all cases! We can however cover the vast majority.

Current non covered cases and problems :
- We assume that if there is more than 2 returned types, we cannot do anything. Even if it could technically be possible.
- We assume that any returned type that doesn't fit our "returnable" types list is a class. We don't check at all if this class actualy exists.
- We don't handle spaces in types. The types stop at the first space.
- That means we don't handle (yet) the callable type with spaces (cf https://github.com/symfony/symfony/issues/29969)
- Vendor code extending other vendor core triggers the deprecations 😕

Commits
-------

aa338c8b42 Import return annotations from vendors
10fc13e4a7 [ErrorHandler] Handle return types in DebugClassLoader
This commit is contained in:
Nicolas Grekas 2019-08-14 15:35:48 +02:00
commit 320e49576e
84 changed files with 1129 additions and 22 deletions

View File

@ -39,6 +39,8 @@ class ContainerAwareEventManager extends EventManager
/**
* {@inheritdoc}
*
* @return void
*/
public function dispatchEvent($eventName, EventArgs $eventArgs = null)
{
@ -59,6 +61,8 @@ class ContainerAwareEventManager extends EventManager
/**
* {@inheritdoc}
*
* @return object[][]
*/
public function getListeners($event = null)
{
@ -81,6 +85,8 @@ class ContainerAwareEventManager extends EventManager
/**
* {@inheritdoc}
*
* @return bool
*/
public function hasListeners($event)
{
@ -89,6 +95,8 @@ class ContainerAwareEventManager extends EventManager
/**
* {@inheritdoc}
*
* @return void
*/
public function addEventListener($events, $listener)
{
@ -109,6 +117,8 @@ class ContainerAwareEventManager extends EventManager
/**
* {@inheritdoc}
*
* @return void
*/
public function removeEventListener($events, $listener)
{

View File

@ -34,6 +34,8 @@ class DbalLogger implements SQLLogger
/**
* {@inheritdoc}
*
* @return void
*/
public function startQuery($sql, array $params = null, array $types = null)
{
@ -48,6 +50,8 @@ class DbalLogger implements SQLLogger
/**
* {@inheritdoc}
*
* @return void
*/
public function stopQuery()
{

View File

@ -29,6 +29,8 @@ abstract class ManagerRegistry extends AbstractManagerRegistry
/**
* {@inheritdoc}
*
* @return object
*/
protected function getService($name)
{
@ -37,6 +39,8 @@ abstract class ManagerRegistry extends AbstractManagerRegistry
/**
* {@inheritdoc}
*
* @return void
*/
protected function resetService($name)
{

View File

@ -28,6 +28,8 @@ final class TestRepositoryFactory implements RepositoryFactory
/**
* {@inheritdoc}
*
* @return ObjectRepository
*/
public function getRepository(EntityManagerInterface $entityManager, $entityName)
{

View File

@ -34,6 +34,8 @@ class StringWrapperType extends StringType
/**
* {@inheritdoc}
*
* @return string
*/
public function getName()
{

View File

@ -27,6 +27,8 @@ class DoctrineFooType extends Type
/**
* {@inheritdoc}
*
* @return string
*/
public function getName()
{
@ -35,6 +37,8 @@ class DoctrineFooType extends Type
/**
* {@inheritdoc}
*
* @return string
*/
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
@ -76,6 +80,8 @@ class DoctrineFooType extends Type
/**
* {@inheritdoc}
*
* @return bool
*/
public function requiresSQLCommentHint(AbstractPlatform $platform)
{

View File

@ -72,6 +72,8 @@ class ChromePhpHandler extends BaseChromePhpHandler
/**
* Override default behavior since we check it in onKernelResponse.
*
* @return bool
*/
protected function headersAccepted()
{

View File

@ -11,6 +11,7 @@
namespace Symfony\Bridge\Monolog\Handler;
use Monolog\Formatter\FormatterInterface;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;
@ -73,6 +74,8 @@ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscribe
/**
* {@inheritdoc}
*
* @return bool
*/
public function isHandling(array $record)
{
@ -81,6 +84,8 @@ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscribe
/**
* {@inheritdoc}
*
* @return bool
*/
public function handle(array $record)
{
@ -142,6 +147,8 @@ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscribe
/**
* {@inheritdoc}
*
* @return void
*/
protected function write(array $record)
{
@ -151,6 +158,8 @@ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscribe
/**
* {@inheritdoc}
*
* @return FormatterInterface
*/
protected function getDefaultFormatter()
{

View File

@ -45,6 +45,9 @@ class HttpCodeActivationStrategy extends ErrorLevelActivationStrategy
$this->exclusions = $exclusions;
}
/**
* @return bool
*/
public function isHandlerActivated(array $record)
{
$isActivated = parent::isHandlerActivated($record);

View File

@ -34,6 +34,9 @@ class NotFoundActivationStrategy extends ErrorLevelActivationStrategy
$this->blacklist = '{('.implode('|', $excludedUrls).')}i';
}
/**
* @return bool
*/
public function isHandlerActivated(array $record)
{
$isActivated = parent::isHandlerActivated($record);

View File

@ -74,6 +74,8 @@ class FirePHPHandler extends BaseFirePHPHandler
/**
* Override default behavior since we check the user agent in onKernelResponse.
*
* @return bool
*/
protected function headersAccepted()
{

View File

@ -11,6 +11,7 @@
namespace Symfony\Bridge\Monolog\Handler;
use Monolog\Formatter\FormatterInterface;
use Monolog\Handler\AbstractHandler;
use Monolog\Logger;
use Symfony\Bridge\Monolog\Formatter\VarDumperFormatter;
@ -38,6 +39,8 @@ class ServerLogHandler extends AbstractHandler
/**
* {@inheritdoc}
*
* @return bool
*/
public function handle(array $record)
{
@ -77,6 +80,8 @@ class ServerLogHandler extends AbstractHandler
/**
* {@inheritdoc}
*
* @return FormatterInterface
*/
protected function getDefaultFormatter()
{

View File

@ -29,6 +29,8 @@ class LazyLoadingValueHolderGenerator extends BaseGenerator
/**
* {@inheritdoc}
*
* @return void
*/
public function generate(\ReflectionClass $originalClass, ClassGenerator $classGenerator)
{

View File

@ -31,6 +31,8 @@ class AssetExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigFunction[]
*/
public function getFunctions()
{

View File

@ -40,6 +40,8 @@ class CodeExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigFilter[]
*/
public function getFilters()
{

View File

@ -17,6 +17,7 @@ use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\Template;
use Twig\TokenParser\TokenParserInterface;
use Twig\TwigFunction;
/**
@ -35,6 +36,9 @@ class DumpExtension extends AbstractExtension
$this->dumper = $dumper;
}
/**
* @return TwigFunction[]
*/
public function getFunctions()
{
return [
@ -42,6 +46,9 @@ class DumpExtension extends AbstractExtension
];
}
/**
* @return TokenParserInterface[]
*/
public function getTokenParsers()
{
return [new DumpTokenParser()];

View File

@ -24,6 +24,8 @@ class ExpressionExtension extends AbstractExtension
{
/**
* {@inheritdoc}
*
* @return TwigFunction[]
*/
public function getFunctions()
{

View File

@ -15,6 +15,7 @@ use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser;
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
use Symfony\Component\Form\FormView;
use Twig\Extension\AbstractExtension;
use Twig\TokenParser\TokenParserInterface;
use Twig\TwigFilter;
use Twig\TwigFunction;
use Twig\TwigTest;
@ -29,6 +30,8 @@ class FormExtension extends AbstractExtension
{
/**
* {@inheritdoc}
*
* @return TokenParserInterface[]
*/
public function getTokenParsers()
{
@ -40,6 +43,8 @@ class FormExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigFunction[]
*/
public function getFunctions()
{
@ -60,6 +65,8 @@ class FormExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigFilter[]
*/
public function getFilters()
{
@ -71,6 +78,8 @@ class FormExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigTest[]
*/
public function getTests()
{

View File

@ -57,6 +57,8 @@ class HttpFoundationExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigFunction[]
*/
public function getFunctions()
{

View File

@ -22,6 +22,9 @@ use Twig\TwigFunction;
*/
class HttpKernelExtension extends AbstractExtension
{
/**
* @return TwigFunction[]
*/
public function getFunctions()
{
return [

View File

@ -31,6 +31,8 @@ class LogoutUrlExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigFunction[]
*/
public function getFunctions()
{

View File

@ -34,6 +34,8 @@ class RoutingExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigFunction[]
*/
public function getFunctions()
{

View File

@ -50,6 +50,8 @@ class SecurityExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigFunction[]
*/
public function getFunctions()
{

View File

@ -14,6 +14,7 @@ namespace Symfony\Bridge\Twig\Extension;
use Symfony\Bridge\Twig\TokenParser\StopwatchTokenParser;
use Symfony\Component\Stopwatch\Stopwatch;
use Twig\Extension\AbstractExtension;
use Twig\TokenParser\TokenParserInterface;
/**
* Twig extension for the stopwatch helper.
@ -36,6 +37,9 @@ class StopwatchExtension extends AbstractExtension
return $this->stopwatch;
}
/**
* @return TokenParserInterface[]
*/
public function getTokenParsers()
{
return [

View File

@ -68,6 +68,8 @@ class TranslationExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigFilter[]
*/
public function getFilters()
{
@ -100,6 +102,8 @@ class TranslationExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return NodeVisitorInterface[]
*/
public function getNodeVisitors()
{

View File

@ -33,6 +33,8 @@ class WebLinkExtension extends AbstractExtension
/**
* {@inheritdoc}
*
* @return TwigFunction[]
*/
public function getFunctions()
{

View File

@ -31,6 +31,9 @@ class WorkflowExtension extends AbstractExtension
$this->workflowRegistry = $workflowRegistry;
}
/**
* @return TwigFunction[]
*/
public function getFunctions()
{
return [

View File

@ -25,6 +25,8 @@ class YamlExtension extends AbstractExtension
{
/**
* {@inheritdoc}
*
* @return TwigFilter[]
*/
public function getFilters()
{

View File

@ -39,6 +39,8 @@ class TranslationDefaultDomainNodeVisitor extends AbstractNodeVisitor
/**
* {@inheritdoc}
*
* @return Node
*/
protected function doEnterNode(Node $node, Environment $env)
{
@ -91,6 +93,8 @@ class TranslationDefaultDomainNodeVisitor extends AbstractNodeVisitor
/**
* {@inheritdoc}
*
* @return Node|null
*/
protected function doLeaveNode(Node $node, Environment $env)
{

View File

@ -49,6 +49,8 @@ class TranslationNodeVisitor extends AbstractNodeVisitor
/**
* {@inheritdoc}
*
* @return Node
*/
protected function doEnterNode(Node $node, Environment $env)
{
@ -89,6 +91,8 @@ class TranslationNodeVisitor extends AbstractNodeVisitor
/**
* {@inheritdoc}
*
* @return Node|null
*/
protected function doLeaveNode(Node $node, Environment $env)
{

View File

@ -12,6 +12,7 @@
namespace Symfony\Bridge\Twig\TokenParser;
use Symfony\Bridge\Twig\Node\DumpNode;
use Twig\Node\Node;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
@ -30,6 +31,8 @@ class DumpTokenParser extends AbstractTokenParser
{
/**
* {@inheritdoc}
*
* @return Node
*/
public function parse(Token $token)
{
@ -44,6 +47,8 @@ class DumpTokenParser extends AbstractTokenParser
/**
* {@inheritdoc}
*
* @return string
*/
public function getTag()
{

View File

@ -13,6 +13,7 @@ namespace Symfony\Bridge\Twig\TokenParser;
use Symfony\Bridge\Twig\Node\StopwatchNode;
use Twig\Node\Expression\AssignNameExpression;
use Twig\Node\Node;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
@ -30,6 +31,9 @@ class StopwatchTokenParser extends AbstractTokenParser
$this->stopwatchIsAvailable = $stopwatchIsAvailable;
}
/**
* @return Node
*/
public function parse(Token $token)
{
$lineno = $token->getLine();
@ -56,6 +60,9 @@ class StopwatchTokenParser extends AbstractTokenParser
return $token->test('endstopwatch');
}
/**
* @return string
*/
public function getTag()
{
return 'stopwatch';

View File

@ -15,6 +15,7 @@ use Symfony\Bridge\Twig\Node\TransNode;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Node;
use Twig\Node\TextNode;
use Twig\Token;
@ -29,6 +30,8 @@ class TransChoiceTokenParser extends TransTokenParser
{
/**
* {@inheritdoc}
*
* @return Node
*/
public function parse(Token $token)
{
@ -82,6 +85,8 @@ class TransChoiceTokenParser extends TransTokenParser
/**
* {@inheritdoc}
*
* @return string
*/
public function getTag()
{

View File

@ -12,6 +12,7 @@
namespace Symfony\Bridge\Twig\TokenParser;
use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
use Twig\Node\Node;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
@ -24,6 +25,8 @@ class TransDefaultDomainTokenParser extends AbstractTokenParser
{
/**
* {@inheritdoc}
*
* @return Node
*/
public function parse(Token $token)
{
@ -36,6 +39,8 @@ class TransDefaultDomainTokenParser extends AbstractTokenParser
/**
* {@inheritdoc}
*
* @return string
*/
public function getTag()
{

View File

@ -15,6 +15,7 @@ use Symfony\Bridge\Twig\Node\TransNode;
use Twig\Error\SyntaxError;
use Twig\Node\Expression\AbstractExpression;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Node;
use Twig\Node\TextNode;
use Twig\Token;
use Twig\TokenParser\AbstractTokenParser;
@ -28,6 +29,8 @@ class TransTokenParser extends AbstractTokenParser
{
/**
* {@inheritdoc}
*
* @return Node
*/
public function parse(Token $token)
{
@ -86,6 +89,8 @@ class TransTokenParser extends AbstractTokenParser
/**
* {@inheritdoc}
*
* @return string
*/
public function getTag()
{

View File

@ -43,6 +43,8 @@ class LegacyRouteLoaderContainer implements ContainerInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function has($id)
{

View File

@ -47,6 +47,8 @@ class FilesystemLoader extends BaseFilesystemLoader
* {@inheritdoc}
*
* The name parameter might also be a TemplateReferenceInterface.
*
* @return bool
*/
public function exists($name)
{

View File

@ -62,6 +62,8 @@ class WebProfilerExtension extends ProfilerExtension
/**
* {@inheritdoc}
*
* @return TwigFunction[]
*/
public function getFunctions()
{

View File

@ -144,6 +144,8 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg
/**
* {@inheritdoc}
*
* @return bool
*/
public function commit()
{

View File

@ -151,6 +151,8 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
/**
* {@inheritdoc}
*
* @return bool
*/
public function commit()
{
@ -213,6 +215,8 @@ abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagA
* {@inheritdoc}
*
* Overloaded in order to deal with tags for adjusted doDelete() signature.
*
* @return bool
*/
public function deleteItems(array $keys)
{

View File

@ -39,6 +39,8 @@ interface AdapterInterface extends CacheItemPoolInterface
* {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/
public function clear(/*string $prefix = ''*/);
}

View File

@ -96,6 +96,8 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItems(array $keys)
{
@ -108,6 +110,8 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
/**
* {@inheritdoc}
*
* @return bool
*/
public function save(CacheItemInterface $item)
{
@ -139,6 +143,8 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
/**
* {@inheritdoc}
*
* @return bool
*/
public function saveDeferred(CacheItemInterface $item)
{
@ -147,6 +153,8 @@ class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInter
/**
* {@inheritdoc}
*
* @return bool
*/
public function commit()
{

View File

@ -178,6 +178,8 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function hasItem($key)
{
@ -194,6 +196,8 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
* {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/
public function clear(/*string $prefix = ''*/)
{
@ -214,6 +218,8 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItem($key)
{
@ -229,6 +235,8 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItems(array $keys)
{
@ -244,6 +252,8 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function save(CacheItemInterface $item)
{
@ -259,6 +269,8 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function saveDeferred(CacheItemInterface $item)
{
@ -274,6 +286,8 @@ class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function commit()
{

View File

@ -67,6 +67,8 @@ class NullAdapter implements AdapterInterface, CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function hasItem($key)
{
@ -77,6 +79,8 @@ class NullAdapter implements AdapterInterface, CacheInterface
* {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/
public function clear(/*string $prefix = ''*/)
{
@ -85,6 +89,8 @@ class NullAdapter implements AdapterInterface, CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItem($key)
{
@ -93,6 +99,8 @@ class NullAdapter implements AdapterInterface, CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItems(array $keys)
{
@ -101,6 +109,8 @@ class NullAdapter implements AdapterInterface, CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function save(CacheItemInterface $item)
{
@ -109,6 +119,8 @@ class NullAdapter implements AdapterInterface, CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function saveDeferred(CacheItemInterface $item)
{
@ -117,6 +129,8 @@ class NullAdapter implements AdapterInterface, CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function commit()
{

View File

@ -165,6 +165,8 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
/**
* {@inheritdoc}
*
* @return bool
*/
public function hasItem($key)
{
@ -180,6 +182,8 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItem($key)
{
@ -195,6 +199,8 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItems(array $keys)
{
@ -225,6 +231,8 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
/**
* {@inheritdoc}
*
* @return bool
*/
public function save(CacheItemInterface $item)
{
@ -237,6 +245,8 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
/**
* {@inheritdoc}
*
* @return bool
*/
public function saveDeferred(CacheItemInterface $item)
{
@ -249,6 +259,8 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
/**
* {@inheritdoc}
*
* @return bool
*/
public function commit()
{

View File

@ -139,6 +139,8 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function hasItem($key)
{
@ -149,6 +151,8 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
* {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/
public function clear(/*string $prefix = ''*/)
{
@ -163,6 +167,8 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItem($key)
{
@ -171,6 +177,8 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItems(array $keys)
{
@ -185,6 +193,8 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function save(CacheItemInterface $item)
{
@ -193,6 +203,8 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function saveDeferred(CacheItemInterface $item)
{
@ -201,6 +213,8 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
/**
* {@inheritdoc}
*
* @return bool
*/
public function commit()
{

View File

@ -151,6 +151,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
/**
* {@inheritdoc}
*
* @return bool
*/
public function hasItem($key)
{
@ -215,6 +217,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
* {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/
public function clear(/*string $prefix = ''*/)
{
@ -239,6 +243,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItem($key)
{
@ -247,6 +253,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItems(array $keys)
{
@ -261,6 +269,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
/**
* {@inheritdoc}
*
* @return bool
*/
public function save(CacheItemInterface $item)
{
@ -274,6 +284,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
/**
* {@inheritdoc}
*
* @return bool
*/
public function saveDeferred(CacheItemInterface $item)
{
@ -287,6 +299,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterfac
/**
* {@inheritdoc}
*
* @return bool
*/
public function commit()
{

View File

@ -89,6 +89,8 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt
/**
* {@inheritdoc}
*
* @return bool
*/
public function hasItem($key)
{
@ -102,6 +104,8 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItem($key)
{
@ -115,6 +119,8 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt
/**
* {@inheritdoc}
*
* @return bool
*/
public function save(CacheItemInterface $item)
{
@ -128,6 +134,8 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt
/**
* {@inheritdoc}
*
* @return bool
*/
public function saveDeferred(CacheItemInterface $item)
{
@ -169,6 +177,8 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt
* {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/
public function clear(/*string $prefix = ''*/)
{
@ -187,6 +197,8 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItems(array $keys)
{
@ -201,6 +213,8 @@ class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInt
/**
* {@inheritdoc}
*
* @return bool
*/
public function commit()
{

View File

@ -36,6 +36,8 @@ final class CacheItem implements ItemInterface
/**
* {@inheritdoc}
*
* @return string
*/
public function getKey()
{
@ -52,6 +54,8 @@ final class CacheItem implements ItemInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function isHit()
{
@ -60,6 +64,8 @@ final class CacheItem implements ItemInterface
/**
* {@inheritdoc}
*
* @return static
*/
public function set($value)
{
@ -70,6 +76,8 @@ final class CacheItem implements ItemInterface
/**
* {@inheritdoc}
*
* @return static
*/
public function expiresAt($expiration)
{
@ -86,6 +94,8 @@ final class CacheItem implements ItemInterface
/**
* {@inheritdoc}
*
* @return static
*/
public function expiresAfter($time)
{

View File

@ -58,6 +58,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doContains($id)
{
@ -66,6 +68,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doSave($id, $data, $lifeTime = 0)
{
@ -80,6 +84,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doDelete($id)
{
@ -88,6 +94,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/**
* {@inheritdoc}
*
* @return bool
*/
protected function doFlush()
{
@ -96,6 +104,8 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese
/**
* {@inheritdoc}
*
* @return array|null
*/
protected function doGetStats()
{

View File

@ -85,6 +85,8 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
/**
* {@inheritdoc}
*
* @return bool
*/
public function set($key, $value, $ttl = null)
{
@ -108,6 +110,8 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
/**
* {@inheritdoc}
*
* @return bool
*/
public function delete($key)
{
@ -122,6 +126,8 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
/**
* {@inheritdoc}
*
* @return bool
*/
public function clear()
{
@ -130,6 +136,8 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
/**
* {@inheritdoc}
*
* @return iterable
*/
public function getMultiple($keys, $default = null)
{
@ -178,6 +186,8 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
/**
* {@inheritdoc}
*
* @return bool
*/
public function setMultiple($values, $ttl = null)
{
@ -229,6 +239,8 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteMultiple($keys)
{
@ -249,6 +261,8 @@ class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterf
/**
* {@inheritdoc}
*
* @return bool
*/
public function has($key)
{

View File

@ -69,6 +69,8 @@ abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterfac
/**
* {@inheritdoc}
*
* @return bool
*/
public function set($key, $value, $ttl = null)
{
@ -79,6 +81,8 @@ abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterfac
/**
* {@inheritdoc}
*
* @return iterable
*/
public function getMultiple($keys, $default = null)
{
@ -105,6 +109,8 @@ abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterfac
/**
* {@inheritdoc}
*
* @return bool
*/
public function setMultiple($values, $ttl = null)
{
@ -142,6 +148,8 @@ abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterfac
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteMultiple($keys)
{

View File

@ -66,6 +66,8 @@ class ArrayCache implements Psr16CacheInterface, LoggerAwareInterface, Resettabl
/**
* {@inheritdoc}
*
* @return iterable
*/
public function getMultiple($keys, $default = null)
{
@ -85,6 +87,8 @@ class ArrayCache implements Psr16CacheInterface, LoggerAwareInterface, Resettabl
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteMultiple($keys)
{
@ -100,6 +104,8 @@ class ArrayCache implements Psr16CacheInterface, LoggerAwareInterface, Resettabl
/**
* {@inheritdoc}
*
* @return bool
*/
public function set($key, $value, $ttl = null)
{
@ -112,6 +118,8 @@ class ArrayCache implements Psr16CacheInterface, LoggerAwareInterface, Resettabl
/**
* {@inheritdoc}
*
* @return bool
*/
public function setMultiple($values, $ttl = null)
{

View File

@ -82,6 +82,8 @@ class ChainCache implements Psr16CacheInterface, PruneableInterface, ResettableI
/**
* {@inheritdoc}
*
* @return iterable
*/
public function getMultiple($keys, $default = null)
{
@ -123,6 +125,8 @@ class ChainCache implements Psr16CacheInterface, PruneableInterface, ResettableI
/**
* {@inheritdoc}
*
* @return bool
*/
public function has($key)
{
@ -137,6 +141,8 @@ class ChainCache implements Psr16CacheInterface, PruneableInterface, ResettableI
/**
* {@inheritdoc}
*
* @return bool
*/
public function clear()
{
@ -152,6 +158,8 @@ class ChainCache implements Psr16CacheInterface, PruneableInterface, ResettableI
/**
* {@inheritdoc}
*
* @return bool
*/
public function delete($key)
{
@ -167,6 +175,8 @@ class ChainCache implements Psr16CacheInterface, PruneableInterface, ResettableI
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteMultiple($keys)
{
@ -185,6 +195,8 @@ class ChainCache implements Psr16CacheInterface, PruneableInterface, ResettableI
/**
* {@inheritdoc}
*
* @return bool
*/
public function set($key, $value, $ttl = null)
{
@ -200,6 +212,8 @@ class ChainCache implements Psr16CacheInterface, PruneableInterface, ResettableI
/**
* {@inheritdoc}
*
* @return bool
*/
public function setMultiple($values, $ttl = null)
{

View File

@ -32,6 +32,8 @@ class NullCache implements Psr16CacheInterface
/**
* {@inheritdoc}
*
* @return iterable
*/
public function getMultiple($keys, $default = null)
{
@ -42,6 +44,8 @@ class NullCache implements Psr16CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function has($key)
{
@ -50,6 +54,8 @@ class NullCache implements Psr16CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function clear()
{
@ -58,6 +64,8 @@ class NullCache implements Psr16CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function delete($key)
{
@ -66,6 +74,8 @@ class NullCache implements Psr16CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteMultiple($keys)
{
@ -74,6 +84,8 @@ class NullCache implements Psr16CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function set($key, $value, $ttl = null)
{
@ -82,6 +94,8 @@ class NullCache implements Psr16CacheInterface
/**
* {@inheritdoc}
*
* @return bool
*/
public function setMultiple($values, $ttl = null)
{

View File

@ -87,6 +87,8 @@ class PhpArrayCache implements Psr16CacheInterface, PruneableInterface, Resettab
/**
* {@inheritdoc}
*
* @return iterable
*/
public function getMultiple($keys, $default = null)
{
@ -109,6 +111,8 @@ class PhpArrayCache implements Psr16CacheInterface, PruneableInterface, Resettab
/**
* {@inheritdoc}
*
* @return bool
*/
public function has($key)
{
@ -124,6 +128,8 @@ class PhpArrayCache implements Psr16CacheInterface, PruneableInterface, Resettab
/**
* {@inheritdoc}
*
* @return bool
*/
public function delete($key)
{
@ -139,6 +145,8 @@ class PhpArrayCache implements Psr16CacheInterface, PruneableInterface, Resettab
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteMultiple($keys)
{
@ -173,6 +181,8 @@ class PhpArrayCache implements Psr16CacheInterface, PruneableInterface, Resettab
/**
* {@inheritdoc}
*
* @return bool
*/
public function set($key, $value, $ttl = null)
{
@ -188,6 +198,8 @@ class PhpArrayCache implements Psr16CacheInterface, PruneableInterface, Resettab
/**
* {@inheritdoc}
*
* @return bool
*/
public function setMultiple($values, $ttl = null)
{

View File

@ -58,6 +58,8 @@ class TraceableCache implements Psr16CacheInterface, PruneableInterface, Resetta
/**
* {@inheritdoc}
*
* @return bool
*/
public function has($key)
{
@ -71,6 +73,8 @@ class TraceableCache implements Psr16CacheInterface, PruneableInterface, Resetta
/**
* {@inheritdoc}
*
* @return bool
*/
public function delete($key)
{
@ -84,6 +88,8 @@ class TraceableCache implements Psr16CacheInterface, PruneableInterface, Resetta
/**
* {@inheritdoc}
*
* @return bool
*/
public function set($key, $value, $ttl = null)
{
@ -97,6 +103,8 @@ class TraceableCache implements Psr16CacheInterface, PruneableInterface, Resetta
/**
* {@inheritdoc}
*
* @return bool
*/
public function setMultiple($values, $ttl = null)
{
@ -124,6 +132,8 @@ class TraceableCache implements Psr16CacheInterface, PruneableInterface, Resetta
/**
* {@inheritdoc}
*
* @return iterable
*/
public function getMultiple($keys, $default = null)
{
@ -152,6 +162,8 @@ class TraceableCache implements Psr16CacheInterface, PruneableInterface, Resetta
/**
* {@inheritdoc}
*
* @return bool
*/
public function clear()
{
@ -165,6 +177,8 @@ class TraceableCache implements Psr16CacheInterface, PruneableInterface, Resetta
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteMultiple($keys)
{

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Cache\Tests\Adapter;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Adapter\ProxyAdapter;
@ -28,6 +29,9 @@ class ProxyAdapterTest extends AdapterTestCase
'testPrune' => 'ProxyAdapter just proxies',
];
/**
* @return CacheItemPoolInterface
*/
public function createCachePool($defaultLifetime = 0, $testMethod = null)
{
if ('testGetMetadata' === $testMethod) {

View File

@ -13,6 +13,9 @@ class ArrayCache extends CacheProvider
return $this->doContains($id) ? $this->data[$id][0] : false;
}
/**
* @return bool
*/
protected function doContains($id)
{
if (!isset($this->data[$id])) {
@ -24,6 +27,9 @@ class ArrayCache extends CacheProvider
return !$expiry || microtime(true) < $expiry || !$this->doDelete($id);
}
/**
* @return bool
*/
protected function doSave($id, $data, $lifeTime = 0)
{
$this->data[$id] = [$data, $lifeTime ? microtime(true) + $lifeTime : false];
@ -31,6 +37,9 @@ class ArrayCache extends CacheProvider
return true;
}
/**
* @return bool
*/
protected function doDelete($id)
{
unset($this->data[$id]);
@ -38,6 +47,9 @@ class ArrayCache extends CacheProvider
return true;
}
/**
* @return bool
*/
protected function doFlush()
{
$this->data = [];
@ -45,6 +57,9 @@ class ArrayCache extends CacheProvider
return true;
}
/**
* @return array|null
*/
protected function doGetStats()
{
return null;

View File

@ -29,46 +29,73 @@ class ExternalAdapter implements CacheItemPoolInterface
$this->cache = new ArrayAdapter($defaultLifetime);
}
/**
* @return CacheItemInterface
*/
public function getItem($key)
{
return $this->cache->getItem($key);
}
/**
* @return iterable
*/
public function getItems(array $keys = [])
{
return $this->cache->getItems($keys);
}
/**
* @return bool
*/
public function hasItem($key)
{
return $this->cache->hasItem($key);
}
/**
* @return bool
*/
public function clear()
{
return $this->cache->clear();
}
/**
* @return bool
*/
public function deleteItem($key)
{
return $this->cache->deleteItem($key);
}
/**
* @return bool
*/
public function deleteItems(array $keys)
{
return $this->cache->deleteItems($keys);
}
/**
* @return bool
*/
public function save(CacheItemInterface $item)
{
return $this->cache->save($item);
}
/**
* @return bool
*/
public function saveDeferred(CacheItemInterface $item)
{
return $this->cache->saveDeferred($item);
}
/**
* @return bool
*/
public function commit()
{
return $this->cache->commit();

View File

@ -26,6 +26,9 @@ abstract class CacheTestCase extends SimpleCacheTest
}
}
/**
* @return array
*/
public static function validKeys()
{
return array_merge(parent::validKeys(), [["a\0b"]]);

View File

@ -84,6 +84,8 @@ trait AbstractAdapterTrait
/**
* {@inheritdoc}
*
* @return bool
*/
public function save(CacheItemInterface $item)
{
@ -97,6 +99,8 @@ trait AbstractAdapterTrait
/**
* {@inheritdoc}
*
* @return bool
*/
public function saveDeferred(CacheItemInterface $item)
{

View File

@ -82,6 +82,8 @@ trait AbstractTrait
/**
* {@inheritdoc}
*
* @return bool
*/
public function hasItem($key)
{
@ -104,6 +106,8 @@ trait AbstractTrait
* {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/
public function clear(/*string $prefix = ''*/)
{
@ -133,6 +137,8 @@ trait AbstractTrait
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItem($key)
{
@ -141,6 +147,8 @@ trait AbstractTrait
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItems(array $keys)
{

View File

@ -53,6 +53,8 @@ trait ArrayTrait
/**
* {@inheritdoc}
*
* @return bool
*/
public function hasItem($key)
{
@ -68,6 +70,8 @@ trait ArrayTrait
* {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/
public function clear(/*string $prefix = ''*/)
{
@ -88,6 +92,8 @@ trait ArrayTrait
/**
* {@inheritdoc}
*
* @return bool
*/
public function deleteItem($key)
{

View File

@ -124,6 +124,8 @@ EOF;
* {@inheritdoc}
*
* @param string $prefix
*
* @return bool
*/
public function clear(/*string $prefix = ''*/)
{

View File

@ -61,6 +61,8 @@ class ConsoleLogger extends AbstractLogger
/**
* {@inheritdoc}
*
* @return void
*/
public function log($level, $message, array $context = [])
{

View File

@ -26,6 +26,9 @@ class BufferingLogger extends AbstractLogger
{
private $logs = [];
/**
* @return void
*/
public function log($level, $message, array $context = [])
{
$this->logs[] = [$level, $message, $context];

View File

@ -27,9 +27,47 @@ use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation;
*/
class DebugClassLoader
{
private const SPECIAL_RETURN_TYPES = [
'mixed' => 'mixed',
'void' => 'void',
'null' => 'null',
'resource' => 'resource',
'static' => 'object',
'$this' => 'object',
'boolean' => 'bool',
'true' => 'bool',
'false' => 'bool',
'integer' => 'int',
'array' => 'array',
'bool' => 'bool',
'callable' => 'callable',
'float' => 'float',
'int' => 'integer',
'iterable' => 'iterable',
'object' => 'object',
'string' => 'string',
'self' => 'self',
'parent' => 'parent',
];
private const BUILTIN_RETURN_TYPES = [
'void' => true,
'array' => true,
'bool' => true,
'callable' => true,
'float' => true,
'int' => true,
'iterable' => true,
'object' => true,
'string' => true,
'self' => true,
'parent' => true,
];
private $classLoader;
private $isFinder;
private $loaded = [];
private $compatPatch;
private static $caseCheck;
private static $checkedClasses = [];
private static $final = [];
@ -40,11 +78,14 @@ class DebugClassLoader
private static $annotatedParameters = [];
private static $darwinCache = ['/' => ['/', []]];
private static $method = [];
private static $returnTypes = [];
private static $methodTraits = [];
public function __construct(callable $classLoader)
{
$this->classLoader = $classLoader;
$this->isFinder = \is_array($classLoader) && method_exists($classLoader[0], 'findFile');
$this->compatPatch = getenv('SYMFONY_PATCH_TYPE_DECLARATIONS_COMPAT') ?: null;
if (!isset(self::$caseCheck)) {
$file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), \DIRECTORY_SEPARATOR);
@ -218,11 +259,11 @@ class DebugClassLoader
$deprecations = [];
// Don't trigger deprecations for classes in the same vendor
if (2 > $len = 1 + (strpos($class, '\\') ?: strpos($class, '_'))) {
$len = 0;
$ns = '';
if (2 > $vendorLen = 1 + (strpos($class, '\\') ?: strpos($class, '_'))) {
$vendorLen = 0;
$vendor = '';
} else {
$ns = str_replace('_', '\\', substr($class, 0, $len));
$vendor = str_replace('_', '\\', substr($class, 0, $vendorLen));
}
// Detect annotations on the class
@ -252,7 +293,7 @@ class DebugClassLoader
}
}
$parent = get_parent_class($class);
$parent = get_parent_class($class) ?: null;
$parentAndOwnInterfaces = $this->getOwnInterfaces($class, $parent);
if ($parent) {
$parentAndOwnInterfaces[$parent] = $parent;
@ -271,13 +312,13 @@ class DebugClassLoader
if (!isset(self::$checkedClasses[$use])) {
$this->checkClass($use);
}
if (isset(self::$deprecated[$use]) && strncmp($ns, str_replace('_', '\\', $use), $len) && !isset(self::$deprecated[$class])) {
if (isset(self::$deprecated[$use]) && strncmp($vendor, str_replace('_', '\\', $use), $vendorLen) && !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)) {
if (isset(self::$internal[$use]) && strncmp($vendor, str_replace('_', '\\', $use), $vendorLen)) {
$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 (isset(self::$method[$use])) {
@ -305,15 +346,24 @@ class DebugClassLoader
}
if (trait_exists($class)) {
$file = $refl->getFileName();
foreach ($refl->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $method) {
if ($method->getFileName() === $file) {
self::$methodTraits[$file][$method->getStartLine()] = $class;
}
}
return $deprecations;
}
// Inherit @final, @internal and @param annotations for methods
// Inherit @final, @internal, @param and @return annotations for methods
self::$finalMethods[$class] = [];
self::$internalMethods[$class] = [];
self::$annotatedParameters[$class] = [];
self::$returnTypes[$class] = [];
foreach ($parentAndOwnInterfaces as $use) {
foreach (['finalMethods', 'internalMethods', 'annotatedParameters'] as $property) {
foreach (['finalMethods', 'internalMethods', 'annotatedParameters', 'returnTypes'] as $property) {
if (isset(self::${$property}[$use])) {
self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use];
}
@ -325,6 +375,16 @@ class DebugClassLoader
continue;
}
if (null === $ns = self::$methodTraits[$method->getFileName()][$method->getStartLine()] ?? null) {
$ns = $vendor;
$len = $vendorLen;
} elseif (2 > $len = 1 + (strpos($ns, '\\') ?: strpos($ns, '_'))) {
$len = 0;
$ns = '';
} else {
$ns = str_replace('_', '\\', substr($ns, 0, $len));
}
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);
@ -353,10 +413,34 @@ class DebugClassLoader
}
}
if (isset(self::$returnTypes[$class][$method->name]) && !$method->hasReturnType() && !($doc && preg_match('/\n\s+\* @return +(\S+)/', $doc))) {
list($normalizedType, $returnType, $declaringClass, $declaringFile) = self::$returnTypes[$class][$method->name];
if (null !== $this->compatPatch && 0 === strpos($class, $this->compatPatch)) {
self::fixReturnStatements($method, $normalizedType);
}
if (strncmp($ns, $declaringClass, $len)) {
if (null !== $this->compatPatch && 0 === strpos($class, $this->compatPatch)) {
self::patchMethod($method, $returnType, $declaringFile);
}
$deprecations[] = sprintf('Method "%s::%s()" will return "%s" as of its next major version. Doing the same in child class "%s" will be required when upgrading.', $declaringClass, $method->name, $normalizedType, $class);
}
}
if (!$doc) {
continue;
}
if (!$method->hasReturnType() && false !== strpos($doc, '@return') && preg_match('/\n\s+\* @return +(\S+)/', $doc, $matches)) {
$this->setReturnType($matches[1], $method, $parent);
if (null !== $this->compatPatch && 0 === strpos($class, $this->compatPatch)) {
self::fixReturnStatements($method, self::$returnTypes[$class][$method->name][0] ?? '?');
}
}
$finalOrInternal = false;
foreach (['final', 'internal'] as $annotation) {
@ -382,7 +466,7 @@ class DebugClassLoader
foreach ($matches as list(, $parameterType, $parameterName)) {
if (!isset($definedParameters[$parameterName])) {
$parameterType = trim($parameterType);
self::$annotatedParameters[$class][$method->name][$parameterName] = sprintf('The "%%s::%s()" method will require a new "%s$%s" argument in the next major version of its parent class "%s", not defining it is deprecated.', $method->name, $parameterType ? $parameterType.' ' : '', $parameterName, $method->class);
self::$annotatedParameters[$class][$method->name][$parameterName] = sprintf('The "%%s::%s()" method will require a new "%s$%s" argument in the next major version of its parent class "%s", not defining it is deprecated.', $method->name, $parameterType ? $parameterType.' ' : '', $parameterName, $class);
}
}
}
@ -496,11 +580,9 @@ class DebugClassLoader
/**
* `class_implements` includes interfaces from the parents so we have to manually exclude them.
*
* @param string|false $parent
*
* @return string[]
*/
private function getOwnInterfaces(string $class, $parent): array
private function getOwnInterfaces(string $class, ?string $parent): array
{
$ownInterfaces = class_implements($class, false);
@ -518,4 +600,234 @@ class DebugClassLoader
return $ownInterfaces;
}
private function setReturnType(string $types, \ReflectionMethod $method, ?string $parent): void
{
$nullable = false;
$typesMap = [];
foreach (explode('|', $types) as $t) {
$typesMap[$this->normalizeType($t, $method->class, $parent)] = $t;
}
if (isset($typesMap['array']) && (isset($typesMap['Traversable']) || isset($typesMap['\Traversable']))) {
$typesMap['iterable'] = 'array' !== $typesMap['array'] ? $typesMap['array'] : 'iterable';
unset($typesMap['array'], $typesMap['Traversable'], $typesMap['\Traversable']);
}
if (isset($typesMap['array']) && isset($typesMap['iterable'])) {
if ('[]' === substr($typesMap['array'], -2)) {
$typesMap['iterable'] = $typesMap['array'];
}
unset($typesMap['array']);
}
$normalizedType = key($typesMap);
$returnType = current($typesMap);
foreach ($typesMap as $n => $t) {
if ('null' === $n) {
$nullable = true;
} elseif ('null' === $normalizedType) {
$normalizedType = $t;
$returnType = $t;
} elseif ($n !== $normalizedType) {
// ignore multi-types return declarations
return;
}
}
if ('void' === $normalizedType) {
$nullable = false;
} elseif (!isset(self::BUILTIN_RETURN_TYPES[$normalizedType]) && isset(self::SPECIAL_RETURN_TYPES[$normalizedType])) {
// ignore other special return types
return;
}
if ($nullable) {
$normalizedType = '?'.$normalizedType;
$returnType .= '|null';
}
self::$returnTypes[$method->class][$method->name] = [$normalizedType, $returnType, $method->class, $method->getFileName()];
}
private function normalizeType(string $type, string $class, ?string $parent): string
{
if (isset(self::SPECIAL_RETURN_TYPES[$lcType = strtolower($type)])) {
if ('parent' === $lcType = self::SPECIAL_RETURN_TYPES[$lcType]) {
$lcType = null !== $parent ? '\\'.$parent : 'parent';
} elseif ('self' === $lcType) {
$lcType = '\\'.$class;
}
return $lcType;
}
if ('[]' === substr($type, -2)) {
return 'array';
}
if (preg_match('/^(array|iterable|callable) *[<(]/', $lcType, $m)) {
return $m[1];
}
// We could resolve "use" statements to return the FQDN
// but this would be too expensive for a runtime checker
return $type;
}
/**
* Utility method to add @return annotations to the Symfony code-base where it triggers a self-deprecations.
*/
private static function patchMethod(\ReflectionMethod $method, string $returnType, string $declaringFile)
{
static $patchedMethods = [];
static $useStatements = [];
if (!file_exists($file = $method->getFileName()) || isset($patchedMethods[$file][$startLine = $method->getStartLine()])) {
return;
}
$patchedMethods[$file][$startLine] = true;
$patchedMethods[$file][0] = $patchedMethods[$file][0] ?? 0;
$startLine += $patchedMethods[$file][0] - 2;
$returnType = explode('|', $returnType);
$code = file($file);
foreach ($returnType as $i => $type) {
if (preg_match('/((?:\[\])+)$/', $type, $m)) {
$type = substr($type, 0, -\strlen($m[1]));
$format = '%s'.$m[1];
} elseif (preg_match('/^(array|iterable)<([^,>]++)>$/', $type, $m)) {
$type = $m[2];
$format = $m[1].'<%s>';
} else {
$format = null;
}
if (isset(self::SPECIAL_RETURN_TYPES[$type]) || ('\\' === $type[0] && !$p = strrpos($type, '\\', 1))) {
continue;
}
list($namespace, $useOffset, $useMap) = $useStatements[$file] ?? $useStatements[$file] = self::getUseStatements($file);
if ('\\' !== $type[0]) {
list($declaringNamespace, , $declaringUseMap) = $useStatements[$declaringFile] ?? $useStatements[$declaringFile] = self::getUseStatements($declaringFile);
$p = strpos($type, '\\', 1);
$alias = $p ? substr($type, 0, $p) : $type;
if (isset($declaringUseMap[$alias])) {
$type = '\\'.$declaringUseMap[$alias].($p ? substr($type, $p) : '');
} else {
$type = '\\'.$declaringNamespace.$type;
}
$p = strrpos($type, '\\', 1);
}
$alias = substr($type, 1 + $p);
$type = substr($type, 1);
if (!isset($useMap[$alias]) && (class_exists($c = $namespace.$alias) || interface_exists($c) || trait_exists($c))) {
$useMap[$alias] = $c;
}
if (!isset($useMap[$alias])) {
$useStatements[$file][2][$alias] = $type;
$code[$useOffset] = "use $type;\n".$code[$useOffset];
++$patchedMethods[$file][0];
} elseif ($useMap[$alias] !== $type) {
$alias .= 'FIXME';
$useStatements[$file][2][$alias] = $type;
$code[$useOffset] = "use $type as $alias;\n".$code[$useOffset];
++$patchedMethods[$file][0];
}
$returnType[$i] = null !== $format ? sprintf($format, $alias) : $alias;
}
$returnType = implode('|', $returnType);
if ($method->getDocComment()) {
$code[$startLine] = " * @return $returnType\n".$code[$startLine];
} else {
$code[$startLine] .= <<<EOTXT
/**
* @return $returnType
*/
EOTXT;
}
$patchedMethods[$file][0] += substr_count($code[$startLine], "\n") - 1;
file_put_contents($file, $code);
}
private static function getUseStatements(string $file): array
{
$namespace = '';
$useMap = [];
$useOffset = 0;
if (!file_exists($file)) {
return [$namespace, $useOffset, $useMap];
}
$file = file($file);
for ($i = 0; $i < \count($file); ++$i) {
if (preg_match('/^(class|interface|trait|abstract) /', $file[$i])) {
break;
}
if (0 === strpos($file[$i], 'namespace ')) {
$namespace = substr($file[$i], \strlen('namespace '), -2).'\\';
$useOffset = $i + 2;
}
if (0 === strpos($file[$i], 'use ')) {
$useOffset = $i;
for (; 0 === strpos($file[$i], 'use '); ++$i) {
$u = explode(' as ', substr($file[$i], 4, -2), 2);
if (1 === \count($u)) {
$p = strrpos($u[0], '\\');
$useMap[substr($u[0], false !== $p ? 1 + $p : 0)] = $u[0];
} else {
$useMap[$u[1]] = $u[0];
}
}
break;
}
}
return [$namespace, $useOffset, $useMap];
}
private static function fixReturnStatements(\ReflectionMethod $method, string $returnType)
{
if (!file_exists($file = $method->getFileName())) {
return;
}
$fixedCode = $code = file($file);
$end = $method->getEndLine();
for ($i = $method->getStartLine(); $i < $end; ++$i) {
if ('void' === $returnType) {
$fixedCode[$i] = str_replace(' return null;', ' return;', $code[$i]);
} elseif ('mixed' === $returnType || '?' === $returnType[0]) {
$fixedCode[$i] = str_replace(' return;', ' return null;', $code[$i]);
} else {
$fixedCode[$i] = str_replace(' return;', " return $returnType!?;", $code[$i]);
}
}
if ($fixedCode !== $code) {
file_put_contents($file, $fixedCode);
}
}
}

View File

@ -33,11 +33,11 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
$notFoundSuffix = '\' not found';
$notFoundSuffixLen = \strlen($notFoundSuffix);
if ($notFoundSuffixLen > $messageLen) {
return;
return null;
}
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
return;
return null;
}
foreach (['class', 'interface', 'trait'] as $typeName) {

View File

@ -30,17 +30,17 @@ class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface
$notFoundSuffix = '()';
$notFoundSuffixLen = \strlen($notFoundSuffix);
if ($notFoundSuffixLen > $messageLen) {
return;
return null;
}
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
return;
return null;
}
$prefix = 'Call to undefined function ';
$prefixLen = \strlen($prefix);
if (0 !== strpos($error['message'], $prefix)) {
return;
return null;
}
$fullyQualifiedFunctionName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);

View File

@ -28,7 +28,7 @@ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
{
preg_match('/^Call to undefined method (.*)::(.*)\(\)$/', $error['message'], $matches);
if (!$matches) {
return;
return null;
}
$className = $matches[1];

View File

@ -353,6 +353,40 @@ class DebugClassLoaderTest extends TestCase
{
$this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\DefinitionInEvaluatedCode', true));
}
public function testReturnType()
{
$deprecations = [];
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
$e = error_reporting(E_USER_DEPRECATED);
class_exists('Test\\'.__NAMESPACE__.'\\ReturnType', true);
error_reporting($e);
restore_error_handler();
$this->assertSame([
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeGrandParent::returnTypeGrandParent()" will return "string" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParentInterface::returnTypeParentInterface()" will return "string" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeInterface::returnTypeInterface()" will return "string" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::oneNonNullableReturnableType()" will return "void" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::oneNonNullableReturnableTypeWithNull()" will return "void" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::oneNullableReturnableType()" will return "array" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::oneNullableReturnableTypeWithNull()" will return "?bool" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::oneOtherType()" will return "\ArrayIterator" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::oneOtherTypeWithNull()" will return "?\ArrayIterator" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::manyIterables()" will return "array" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::nullableReturnableTypeNormalization()" will return "object" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::nonNullableReturnableTypeNormalization()" will return "void" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::commonNonObjectReturnedTypeNormalization()" will return "object" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::bracketsNormalization()" will return "array" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::booleanNormalization()" will return "bool" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::callableNormalization1()" will return "callable" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::callableNormalization2()" will return "callable" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::otherTypeNormalization()" will return "\ArrayIterator" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
'Method "Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent::arrayWithLessThanSignNormalization()" will return "array" as of its next major version. Doing the same in child class "Test\Symfony\Component\ErrorHandler\Tests\ReturnType" will be required when upgrading.',
], $deprecations);
}
}
class ClassLoader
@ -435,6 +469,10 @@ class ClassLoader
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualMagicCall' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsVirtualMagicCall extends \\'.__NAMESPACE__.'\Fixtures\VirtualClassMagicCall implements \\'.__NAMESPACE__.'\Fixtures\VirtualInterface {
}');
} elseif ('Test\\'.__NAMESPACE__.'\ReturnType' === $class) {
return $fixtureDir.\DIRECTORY_SEPARATOR.'ReturnType.php';
} elseif ('Test\\'.__NAMESPACE__.'\Fixtures\OutsideInterface' === $class) {
return $fixtureDir.\DIRECTORY_SEPARATOR.'OutsideInterface.php';
}
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace Test\Symfony\Component\ErrorHandler\Tests\Fixtures;
interface OutsideInterface
{
/**
* @return string - should not be reported as it's in a non-Symfony namespace
*/
public function outsideMethod();
}

View File

@ -0,0 +1,46 @@
<?php
namespace Test\Symfony\Component\ErrorHandler\Tests;
use Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeParent;
use Symfony\Component\ErrorHandler\Tests\Fixtures\ReturnTypeInterface;
class ReturnType extends ReturnTypeParent implements ReturnTypeInterface, Fixtures\OutsideInterface
{
public function returnTypeGrandParent() { }
public function returnTypeParentInterface() { }
public function returnTypeInterface() { }
public function realReturnTypeMustBeThere(): string { }
public function realReturnTypeIsAlreadyThere(): float { }
public function realReturnTypeIsAlreadyThereWithNull(): ?iterable { }
public function oneCommonNonObjectReturnedType() { }
public function oneCommonNonObjectReturnedTypeWithNull() { }
public function oneNonNullableReturnableType() { }
public function oneNonNullableReturnableTypeWithNull() { }
public function oneNullableReturnableType() { }
public function oneNullableReturnableTypeWithNull() { }
public function oneOtherType() { }
public function oneOtherTypeWithNull() { }
public function twoNullableReturnableTypes() { }
public function twoNullEdgeCase() { }
public function threeReturnTypes() { }
/**
* @return anything - should not trigger
*/
public function throughDoc() { }
/**
* @return parent - same as parent
*/
public function optOutThroughDoc() { }
public function manyIterables() { }
public function nullableReturnableTypeNormalization() { }
public function nonNullableReturnableTypeNormalization() { }
public function commonNonObjectReturnedTypeNormalization() { }
public function bracketsNormalization() { }
public function booleanNormalization() { }
public function callableNormalization1() { }
public function callableNormalization2() { }
public function otherTypeNormalization() { }
public function arrayWithLessThanSignNormalization() { }
public function outsideMethod() { }
}

View File

@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\ErrorHandler\Tests\Fixtures;
abstract class ReturnTypeGrandParent
{
/**
* @return string
*/
public function returnTypeGrandParent()
{
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace Symfony\Component\ErrorHandler\Tests\Fixtures;
interface ReturnTypeInterface
{
/**
* @return string
*/
public function returnTypeInterface();
}

View File

@ -0,0 +1,201 @@
<?php
namespace Symfony\Component\ErrorHandler\Tests\Fixtures;
abstract class ReturnTypeParent extends ReturnTypeGrandParent implements ReturnTypeParentInterface
{
/**
* No return declared here
*/
public function returnTypeGrandParent()
{
}
/**
* @return string
*/
abstract public function realReturnTypeMustBeThere(): string;
/**
* @return float
*/
public function realReturnTypeIsAlreadyThere()
{
}
/**
* @return iterable|null
*/
abstract public function realReturnTypeIsAlreadyThereWithNull();
/**
* @return mixed
*/
public function oneCommonNonObjectReturnedType()
{
}
/**
* @return resource|null
*/
public function oneCommonNonObjectReturnedTypeWithNull()
{
}
/**
* @return void
*/
public function oneNonNullableReturnableType()
{
}
/**
* @return void|null
*/
public function oneNonNullableReturnableTypeWithNull()
{
}
/**
* @return array The array
*/
public function oneNullableReturnableType()
{
}
/**
* @return bool|null
*/
public function oneNullableReturnableTypeWithNull()
{
}
/**
* @return \ArrayIterator
*/
public function oneOtherType()
{
}
/**
* @return \ArrayIterator|null
*/
public function oneOtherTypeWithNull()
{
}
/**
* @return int|self
*/
public function twoNullableReturnableTypes()
{
}
/**
* @return null|null
*/
public function twoNullEdgeCase()
{
}
/**
* @return bool|string|null
*/
public function threeReturnTypes()
{
}
/**
* @return self
*/
public function throughDoc()
{
}
/**
* @return self
*/
public function optOutThroughDoc()
{
}
/**
* @return \ArrayIterator[]|\DirectoryIterator[]
*/
public function manyIterables()
{
}
/**
* Something before.
*
* @return object
*/
public function nullableReturnableTypeNormalization()
{
}
/**
* @annotation before
* @return VOID
*/
public function nonNullableReturnableTypeNormalization()
{
}
/**
* @return $this
*/
public function commonNonObjectReturnedTypeNormalization()
{
}
/**
* @return \ArrayIterator[]
*/
public function bracketsNormalization()
{
}
/**
* @return false
*/
public function booleanNormalization()
{
}
/**
* @return callable(\Throwable $reason, mixed $value)
*/
public function callableNormalization1()
{
}
/**
* @return callable ($a, $b)
*/
public function callableNormalization2()
{
}
/**
* @return \ArrayIterator
*/
public function otherTypeNormalization()
{
}
/**
* @return array<string, int>
*/
public function arrayWithLessThanSignNormalization()
{
}
/**
* @return int
*/
public function notExtended()
{
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace Symfony\Component\ErrorHandler\Tests\Fixtures;
interface ReturnTypeParentInterface
{
/**
* @return string
*/
public function returnTypeParentInterface();
}

View File

@ -65,6 +65,8 @@ class Logger extends AbstractLogger
/**
* {@inheritdoc}
*
* @return void
*/
public function log($level, $message, array $context = [])
{

View File

@ -41,46 +41,73 @@ class Logger implements LoggerInterface
];
}
/**
* @return void
*/
public function log($level, $message, array $context = [])
{
$this->logs[$level][] = $message;
}
/**
* @return void
*/
public function emergency($message, array $context = [])
{
$this->log('emergency', $message, $context);
}
/**
* @return void
*/
public function alert($message, array $context = [])
{
$this->log('alert', $message, $context);
}
/**
* @return void
*/
public function critical($message, array $context = [])
{
$this->log('critical', $message, $context);
}
/**
* @return void
*/
public function error($message, array $context = [])
{
$this->log('error', $message, $context);
}
/**
* @return void
*/
public function warning($message, array $context = [])
{
$this->log('warning', $message, $context);
}
/**
* @return void
*/
public function notice($message, array $context = [])
{
$this->log('notice', $message, $context);
}
/**
* @return void
*/
public function info($message, array $context = [])
{
$this->log('info', $message, $context);
}
/**
* @return void
*/
public function debug($message, array $context = [])
{
$this->log('debug', $message, $context);

View File

@ -84,13 +84,13 @@ class TimezoneDataGenerator extends AbstractDataGenerator
// Don't generate aliases, as they are resolved during runtime
// Unless an alias is needed as fallback for de-duplication purposes
if (isset($this->localeAliases[$displayLocale]) && !$this->generatingFallback) {
return;
return null;
}
$localeBundle = $reader->read($tempDir, $displayLocale);
if (!isset($localeBundle['zoneStrings']) || null === $localeBundle['zoneStrings']) {
return;
return null;
}
$data = [
@ -115,7 +115,7 @@ class TimezoneDataGenerator extends AbstractDataGenerator
$data['Meta'] = array_diff($data['Meta'], $fallback['Meta']);
}
if (!$data['Names'] && !$data['Meta']) {
return;
return null;
}
$this->zoneIds = array_merge($this->zoneIds, array_keys($data['Names']));

View File

@ -61,6 +61,8 @@ class GenericLinkProvider implements EvolvableLinkProviderInterface
/**
* {@inheritdoc}
*
* @return static
*/
public function withLink(LinkInterface $link)
{
@ -72,6 +74,8 @@ class GenericLinkProvider implements EvolvableLinkProviderInterface
/**
* {@inheritdoc}
*
* @return static
*/
public function withoutLink(LinkInterface $link)
{

View File

@ -92,6 +92,8 @@ class Link implements EvolvableLinkInterface
/**
* {@inheritdoc}
*
* @return static
*/
public function withHref($href)
{
@ -104,6 +106,8 @@ class Link implements EvolvableLinkInterface
/**
* {@inheritdoc}
*
* @return static
*/
public function withRel($rel)
{
@ -115,6 +119,8 @@ class Link implements EvolvableLinkInterface
/**
* {@inheritdoc}
*
* @return static
*/
public function withoutRel($rel)
{
@ -126,6 +132,8 @@ class Link implements EvolvableLinkInterface
/**
* {@inheritdoc}
*
* @return static
*/
public function withAttribute($attribute, $value)
{
@ -137,6 +145,8 @@ class Link implements EvolvableLinkInterface
/**
* {@inheritdoc}
*
* @return static
*/
public function withoutAttribute($attribute)
{

View File

@ -36,6 +36,8 @@ trait ServiceLocatorTrait
/**
* {@inheritdoc}
*
* @return bool
*/
public function has($id)
{