[Debug] Trigger a deprecation when using an internal class/trait/interface
This commit is contained in:
parent
736f0d0d93
commit
b89ba293dd
@ -20,7 +20,7 @@ use Symfony\Component\Form\Exception\RuntimeException;
|
|||||||
*
|
*
|
||||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
*
|
*
|
||||||
* @internal This class is meant for internal use only.
|
* @internal
|
||||||
*/
|
*/
|
||||||
class IdReader
|
class IdReader
|
||||||
{
|
{
|
||||||
|
@ -27,6 +27,7 @@ class DebugClassLoader
|
|||||||
private $classLoader;
|
private $classLoader;
|
||||||
private $isFinder;
|
private $isFinder;
|
||||||
private static $caseCheck;
|
private static $caseCheck;
|
||||||
|
private static $internal = array();
|
||||||
private static $final = array();
|
private static $final = array();
|
||||||
private static $finalMethods = array();
|
private static $finalMethods = array();
|
||||||
private static $deprecated = array();
|
private static $deprecated = array();
|
||||||
@ -166,10 +167,14 @@ class DebugClassLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
$parent = get_parent_class($class);
|
$parent = get_parent_class($class);
|
||||||
|
$doc = $refl->getDocComment();
|
||||||
|
if (preg_match('#\n \* @internal(?:( .+?)\.?)?\r?\n \*(?: @|/$)#s', $doc, $notice)) {
|
||||||
|
self::$internal[$name] = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : '';
|
||||||
|
}
|
||||||
|
|
||||||
// Not an interface nor a trait
|
// Not an interface nor a trait
|
||||||
if (class_exists($name, false)) {
|
if (class_exists($name, false)) {
|
||||||
if (preg_match('#\n \* @final(?:( .+?)\.?)?\r?\n \*(?: @|/$)#s', $refl->getDocComment(), $notice)) {
|
if (preg_match('#\n \* @final(?:( .+?)\.?)?\r?\n \*(?: @|/$)#s', $doc, $notice)) {
|
||||||
self::$final[$name] = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : '';
|
self::$final[$name] = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,50 +208,57 @@ class DebugClassLoader
|
|||||||
|
|
||||||
if (in_array(strtolower($refl->getShortName()), self::$php7Reserved)) {
|
if (in_array(strtolower($refl->getShortName()), self::$php7Reserved)) {
|
||||||
@trigger_error(sprintf('The "%s" class uses the reserved name "%s", it will break on PHP 7 and higher', $name, $refl->getShortName()), E_USER_DEPRECATED);
|
@trigger_error(sprintf('The "%s" class uses the reserved name "%s", it will break on PHP 7 and higher', $name, $refl->getShortName()), E_USER_DEPRECATED);
|
||||||
} elseif (preg_match('#\n \* @deprecated (.*?)\r?\n \*(?: @|/$)#s', $refl->getDocComment(), $notice)) {
|
}
|
||||||
|
if (preg_match('#\n \* @deprecated (.*?)\r?\n \*(?: @|/$)#s', $refl->getDocComment(), $notice)) {
|
||||||
self::$deprecated[$name] = preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]);
|
self::$deprecated[$name] = preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't trigger deprecations for classes in the same vendor
|
||||||
|
if (2 > $len = 1 + (strpos($name, '\\', 1 + strpos($name, '\\')) ?: strpos($name, '_'))) {
|
||||||
|
$len = 0;
|
||||||
|
$ns = '';
|
||||||
} else {
|
} else {
|
||||||
// Don't trigger deprecations for classes in the same vendor
|
switch ($ns = substr($name, 0, $len)) {
|
||||||
if (2 > $len = 1 + (strpos($name, '\\', 1 + strpos($name, '\\')) ?: strpos($name, '_'))) {
|
case 'Symfony\Bridge\\':
|
||||||
$len = 0;
|
case 'Symfony\Bundle\\':
|
||||||
$ns = '';
|
case 'Symfony\Component\\':
|
||||||
} else {
|
$ns = 'Symfony\\';
|
||||||
switch ($ns = substr($name, 0, $len)) {
|
$len = strlen($ns);
|
||||||
case 'Symfony\Bridge\\':
|
break;
|
||||||
case 'Symfony\Bundle\\':
|
}
|
||||||
case 'Symfony\Component\\':
|
}
|
||||||
$ns = 'Symfony\\';
|
|
||||||
$len = strlen($ns);
|
foreach (array_merge(array($parent), class_implements($name, false), class_uses($name, false)) as $use) {
|
||||||
break;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$parent || strncmp($ns, $parent, $len)) {
|
||||||
|
if ($parent && isset(self::$deprecated[$parent]) && strncmp($ns, $parent, $len)) {
|
||||||
|
@trigger_error(sprintf('The "%s" class extends "%s" that is deprecated %s', $name, $parent, self::$deprecated[$parent]), E_USER_DEPRECATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parentInterfaces = array();
|
||||||
|
$deprecatedInterfaces = array();
|
||||||
|
if ($parent) {
|
||||||
|
foreach (class_implements($parent) as $interface) {
|
||||||
|
$parentInterfaces[$interface] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$parent || strncmp($ns, $parent, $len)) {
|
foreach ($refl->getInterfaceNames() as $interface) {
|
||||||
if ($parent && isset(self::$deprecated[$parent]) && strncmp($ns, $parent, $len)) {
|
if (isset(self::$deprecated[$interface]) && strncmp($ns, $interface, $len)) {
|
||||||
@trigger_error(sprintf('The "%s" class extends "%s" that is deprecated %s', $name, $parent, self::$deprecated[$parent]), E_USER_DEPRECATED);
|
$deprecatedInterfaces[] = $interface;
|
||||||
}
|
}
|
||||||
|
foreach (class_implements($interface) as $interface) {
|
||||||
$parentInterfaces = array();
|
$parentInterfaces[$interface] = 1;
|
||||||
$deprecatedInterfaces = array();
|
|
||||||
if ($parent) {
|
|
||||||
foreach (class_implements($parent) as $interface) {
|
|
||||||
$parentInterfaces[$interface] = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($refl->getInterfaceNames() as $interface) {
|
foreach ($deprecatedInterfaces as $interface) {
|
||||||
if (isset(self::$deprecated[$interface]) && strncmp($ns, $interface, $len)) {
|
if (!isset($parentInterfaces[$interface])) {
|
||||||
$deprecatedInterfaces[] = $interface;
|
@trigger_error(sprintf('The "%s" %s "%s" that is deprecated %s', $name, $refl->isInterface() ? 'interface extends' : 'class implements', $interface, self::$deprecated[$interface]), E_USER_DEPRECATED);
|
||||||
}
|
|
||||||
foreach (class_implements($interface) as $interface) {
|
|
||||||
$parentInterfaces[$interface] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($deprecatedInterfaces as $interface) {
|
|
||||||
if (!isset($parentInterfaces[$interface])) {
|
|
||||||
@trigger_error(sprintf('The "%s" %s "%s" that is deprecated %s', $name, $refl->isInterface() ? 'interface extends' : 'class implements', $interface, self::$deprecated[$interface]), E_USER_DEPRECATED);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,6 +312,24 @@ class DebugClassLoaderTest extends TestCase
|
|||||||
|
|
||||||
$this->assertSame($xError, $lastError);
|
$this->assertSame($xError, $lastError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testInternalsUse()
|
||||||
|
{
|
||||||
|
$deprecations = array();
|
||||||
|
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
|
||||||
|
$e = error_reporting(E_USER_DEPRECATED);
|
||||||
|
|
||||||
|
class_exists('Test\\'.__NAMESPACE__.'\\ExtendsInternals', true);
|
||||||
|
|
||||||
|
error_reporting($e);
|
||||||
|
restore_error_handler();
|
||||||
|
|
||||||
|
$this->assertSame($deprecations, array(
|
||||||
|
'The "Symfony\Component\Debug\Tests\Fixtures\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\ExtendsInternals".',
|
||||||
|
'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\ExtendsInternals".',
|
||||||
|
'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".',
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClassLoader
|
class ClassLoader
|
||||||
@ -335,22 +353,12 @@ class ClassLoader
|
|||||||
eval('namespace '.__NAMESPACE__.'; class TestingStacking { function foo() {} }');
|
eval('namespace '.__NAMESPACE__.'; class TestingStacking { function foo() {} }');
|
||||||
} elseif (__NAMESPACE__.'\TestingCaseMismatch' === $class) {
|
} elseif (__NAMESPACE__.'\TestingCaseMismatch' === $class) {
|
||||||
eval('namespace '.__NAMESPACE__.'; class TestingCaseMisMatch {}');
|
eval('namespace '.__NAMESPACE__.'; class TestingCaseMisMatch {}');
|
||||||
} elseif (__NAMESPACE__.'\Fixtures\CaseMismatch' === $class) {
|
|
||||||
return $fixtureDir.'CaseMismatch.php';
|
|
||||||
} elseif (__NAMESPACE__.'\Fixtures\Psr4CaseMismatch' === $class) {
|
} elseif (__NAMESPACE__.'\Fixtures\Psr4CaseMismatch' === $class) {
|
||||||
return $fixtureDir.'psr4'.DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php';
|
return $fixtureDir.'psr4'.DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php';
|
||||||
} elseif (__NAMESPACE__.'\Fixtures\NotPSR0' === $class) {
|
} elseif (__NAMESPACE__.'\Fixtures\NotPSR0' === $class) {
|
||||||
return $fixtureDir.'reallyNotPsr0.php';
|
return $fixtureDir.'reallyNotPsr0.php';
|
||||||
} elseif (__NAMESPACE__.'\Fixtures\NotPSR0bis' === $class) {
|
} elseif (__NAMESPACE__.'\Fixtures\NotPSR0bis' === $class) {
|
||||||
return $fixtureDir.'notPsr0Bis.php';
|
return $fixtureDir.'notPsr0Bis.php';
|
||||||
} elseif (__NAMESPACE__.'\Fixtures\DeprecatedInterface' === $class) {
|
|
||||||
return $fixtureDir.'DeprecatedInterface.php';
|
|
||||||
} elseif (__NAMESPACE__.'\Fixtures\FinalClass' === $class) {
|
|
||||||
return $fixtureDir.'FinalClass.php';
|
|
||||||
} elseif (__NAMESPACE__.'\Fixtures\FinalMethod' === $class) {
|
|
||||||
return $fixtureDir.'FinalMethod.php';
|
|
||||||
} elseif (__NAMESPACE__.'\Fixtures\ExtendedFinalMethod' === $class) {
|
|
||||||
return $fixtureDir.'ExtendedFinalMethod.php';
|
|
||||||
} elseif ('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent' === $class) {
|
} elseif ('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent' === $class) {
|
||||||
eval('namespace Symfony\Bridge\Debug\Tests\Fixtures; class ExtendsDeprecatedParent extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}');
|
eval('namespace Symfony\Bridge\Debug\Tests\Fixtures; class ExtendsDeprecatedParent extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}');
|
||||||
} elseif ('Test\\'.__NAMESPACE__.'\DeprecatedParentClass' === $class) {
|
} elseif ('Test\\'.__NAMESPACE__.'\DeprecatedParentClass' === $class) {
|
||||||
@ -363,6 +371,10 @@ class ClassLoader
|
|||||||
eval('namespace Test\\'.__NAMESPACE__.'; class Float {}');
|
eval('namespace Test\\'.__NAMESPACE__.'; class Float {}');
|
||||||
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsFinalClass' === $class) {
|
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsFinalClass' === $class) {
|
||||||
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsFinalClass extends \\'.__NAMESPACE__.'\Fixtures\FinalClass {}');
|
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsFinalClass extends \\'.__NAMESPACE__.'\Fixtures\FinalClass {}');
|
||||||
|
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsInternals' === $class) {
|
||||||
|
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternals extends \\'.__NAMESPACE__.'\Fixtures\InternalClass implements \\'.__NAMESPACE__.'\Fixtures\InternalInterface {
|
||||||
|
use \\'.__NAMESPACE__.'\Fixtures\InternalTrait;
|
||||||
|
}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
src/Symfony/Component/Debug/Tests/Fixtures/InternalClass.php
Normal file
11
src/Symfony/Component/Debug/Tests/Fixtures/InternalClass.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal since version 3.4.
|
||||||
|
*/
|
||||||
|
class InternalClass
|
||||||
|
{
|
||||||
|
use InternalTrait2;
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
interface InternalInterface
|
||||||
|
{
|
||||||
|
}
|
10
src/Symfony/Component/Debug/Tests/Fixtures/InternalTrait.php
Normal file
10
src/Symfony/Component/Debug/Tests/Fixtures/InternalTrait.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
trait InternalTrait
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Component\Debug\Tests\Fixtures;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
trait InternalTrait2
|
||||||
|
{
|
||||||
|
}
|
@ -18,7 +18,7 @@ use Symfony\Component\Cache\CacheItem;
|
|||||||
/**
|
/**
|
||||||
* @author Alexandre GESLIN <alexandre@gesl.in>
|
* @author Alexandre GESLIN <alexandre@gesl.in>
|
||||||
*
|
*
|
||||||
* @internal This class should be removed in Symfony 4.0.
|
* @internal and will be removed in Symfony 4.0.
|
||||||
*/
|
*/
|
||||||
class ParserCacheAdapter implements CacheItemPoolInterface
|
class ParserCacheAdapter implements CacheItemPoolInterface
|
||||||
{
|
{
|
||||||
|
@ -185,7 +185,7 @@ class ArrayChoiceList implements ChoiceListInterface
|
|||||||
* corresponding values
|
* corresponding values
|
||||||
* @param array $structuredValues The values indexed by the original keys
|
* @param array $structuredValues The values indexed by the original keys
|
||||||
*
|
*
|
||||||
* @internal Must not be used by user-land code
|
* @internal
|
||||||
*/
|
*/
|
||||||
protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues)
|
protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues)
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
|||||||
*
|
*
|
||||||
* @return string The SHA-256 hash
|
* @return string The SHA-256 hash
|
||||||
*
|
*
|
||||||
* @internal Should not be used by user-land code.
|
* @internal
|
||||||
*/
|
*/
|
||||||
public static function generateHash($value, $namespace = '')
|
public static function generateHash($value, $namespace = '')
|
||||||
{
|
{
|
||||||
@ -71,7 +71,7 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface
|
|||||||
* @param array $array The array to flatten
|
* @param array $array The array to flatten
|
||||||
* @param array $output The flattened output
|
* @param array $output The flattened output
|
||||||
*
|
*
|
||||||
* @internal Should not be used by user-land code
|
* @internal
|
||||||
*/
|
*/
|
||||||
private static function flatten(array $array, &$output)
|
private static function flatten(array $array, &$output)
|
||||||
{
|
{
|
||||||
|
@ -30,8 +30,7 @@ use Symfony\Component\Validator\Violation\ConstraintViolationBuilder;
|
|||||||
*
|
*
|
||||||
* @see ExecutionContextInterface
|
* @see ExecutionContextInterface
|
||||||
*
|
*
|
||||||
* @internal You should not instantiate or use this class. Code against
|
* @internal since version 2.5. Code against ExecutionContextInterface instead.
|
||||||
* {@link ExecutionContextInterface} instead.
|
|
||||||
*/
|
*/
|
||||||
class ExecutionContext implements ExecutionContextInterface
|
class ExecutionContext implements ExecutionContextInterface
|
||||||
{
|
{
|
||||||
|
@ -19,8 +19,7 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|||||||
*
|
*
|
||||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
*
|
*
|
||||||
* @internal You should not instantiate or use this class. Code against
|
* @internal version 2.5. Code against ExecutionContextFactoryInterface instead.
|
||||||
* {@link ExecutionContextFactoryInterface} instead.
|
|
||||||
*/
|
*/
|
||||||
class ExecutionContextFactory implements ExecutionContextFactoryInterface
|
class ExecutionContextFactory implements ExecutionContextFactoryInterface
|
||||||
{
|
{
|
||||||
|
@ -22,8 +22,7 @@ use Symfony\Component\Validator\Util\PropertyPath;
|
|||||||
*
|
*
|
||||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||||
*
|
*
|
||||||
* @internal You should not instantiate or use this class. Code against
|
* @internal since version 2.5. Code against ConstraintViolationBuilderInterface instead.
|
||||||
* {@link ConstraintViolationBuilderInterface} instead.
|
|
||||||
*/
|
*/
|
||||||
class ConstraintViolationBuilder implements ConstraintViolationBuilderInterface
|
class ConstraintViolationBuilder implements ConstraintViolationBuilderInterface
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user