-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Debug] Trigger a deprecation for new parameters not defined in sub classes #28329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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); | ||
} | ||
if (isset(self::$internalMethods[$name][$method->name])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated change but the foreach
was useless since we merge parent + traits infos a few lines above.
We should try to enable DebugClassLoader using the phpunit bridge and see how it goes! |
@nicolas-grekas imo we can enable it either by updating the bridge and adding an In both cases, it will require a consequent work to fix all deprecations (using php 7.1, I already have |
7fd5331
to
57d935a
Compare
Ok works for me :) |
623ebe7
to
f69ec6f
Compare
@GuilhemN FYI I push-forced on your fork after squashing the CS commit. See also the 2nd commit I added: it enables |
@@ -11,6 +11,8 @@ | |||
|
|||
namespace Symfony\Component\Debug; | |||
|
|||
use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
related to sebastianbergmann/phpunit-mock-objects#427
f69ec6f
to
7ef91b9
Compare
@@ -984,8 +984,6 @@ public function setCache(array $options) | |||
* @return $this | |||
* | |||
* @see http://tools.ietf.org/html/rfc2616#section-10.3.5 | |||
* | |||
* @final |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Required because StreamedResponse overrides this method. Otherwise, we'll see The "Symfony\Component\HttpFoundation\Response::setNotModified()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\HttpFoundation\StreamedResponse".
as e.g. in https://travis-ci.org/symfony/symfony/jobs/426209061
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(to be discussed; there might be other solutions than this one, wdyt?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could ignore @final
annotations from the same namespace like we do for @deprecated
but imo this is not worth it and maybe we even don't want this behavior
👍 thanks for doing these changes, I hope your second commit will help symfony keep a clean codebase :) |
7ef91b9
to
c8fdf03
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this PR, DebugClassLoader will trigger a deprecation whenever a child method doesn't declare an argument while its parent does so via an @param
annotation. This provides a forward path to adding new arguments to methods of base classes/interfaces in next major versions.
phpunit-bridge part split in #28412 |
self::$finalMethods[$name] = array(); | ||
self::$internalMethods[$name] = array(); | ||
self::$annotatedParameters[$name] = array(); | ||
foreach ($parentAndTraits as $use) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to support @param
in interfaces (imo yes)? If so we should add a separate foreach to inherit annotatedParameters
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep we want to report @param
added to interfaces for sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -258,20 +262,50 @@ private function checkClass($class, $file = null) | |||
} | |||
} | |||
|
|||
// Method from a trait | |||
if ($method->getFilename() !== $refl->getFileName()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be kept imo, I think we also don't want methods from traits being checked against their own @param
annotations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
worth a new test case :)
we also want to report implementations provided by traits that don't provide the argument declared by parents
and also to report missing arguments declared by @param
on traits
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we also want to report implementations provided by traits that don't provide the argument declared by parents
👍, you were right about this change.
and also to report missing arguments declared by @param on traits
Thinking of it again, I prefer not parsing @param
in traits directly since PHP allows a full overwriting of their methods, instead their methods are checked as if they belong to the sub classes using them.
…colas-grekas) This PR was merged into the 4.2-dev branch. Discussion ---------- [PhpUnitBridge] enable DebugClassLoader by default | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | symfony/symfony-docs#10360 With this PR, the phpunit-bridge will enable `DebugClassLoader` by default, making it do its job: throw deprecation notices at autoloading time. On top of #28329, this made me spot some glitches in the code base, fixed here also. This can be disabled by configuring the listener in `phpunit.xml.dist` files, adding `<element key="debug-class-loader"><integer>0</integer></element>` next to `<element key="time-sensitive">...`. Commits ------- 2fb11fc [PhpUnitBridge] enable DebugClassLoader by default
@@ -236,8 +239,12 @@ private function checkClass($class, $file = null) | |||
self::$finalMethods[$name] = array(); | |||
self::$internalMethods[$name] = array(); | |||
self::$annotatedParameters[$name] = array(); | |||
foreach ($parentAndTraits as $use) { | |||
foreach (array('finalMethods', 'internalMethods', 'annotatedParameters') as $property) { | |||
foreach (array( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the CS is a bit weird here, better move the array in some local var
Could you please rebase (+squash) while fixing the small comment above to trigger tests? |
7cef7f2
to
c03d5a1
Compare
c03d5a1
to
1f5d8b6
Compare
Thank you @GuilhemN. |
…efined in sub classes (GuilhemN) This PR was merged into the 4.2-dev branch. Discussion ---------- [Debug] Trigger a deprecation for new parameters not defined in sub classes | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #28316 | License | MIT | Doc PR | - I'm not sure the way #28316 is implemented is the best so here is an alternative. Instead of counting on a call from the child method, it uses the `DebugClassLoader` and `@param` annotations. If a `@param` annotation is used on a parent but is then not actually implemented in the child class, a deprecation will be thrown. Example: ```php class ClassWithAnnotatedParameters { /** * @param string $foo This is a foo parameter. */ public function fooMethod(string $foo) { } /** * @param string $bar parameter not implemented yet */ public function barMethod(/** string $bar = null */) { } /** * @param Quz $quz parameter not implemented yet */ public function quzMethod(/** Quz $quz = null */) { } } ``` ```php class SubClassWithAnnotatedParameters extends ClassWithAnnotatedParameters { public function fooMethod(string $foo) { } public function barMethod($bar = null) { } public function quzMethod() { } } ``` A deprecation will be triggered because ``SubClassWithAnnotatedParameters::quzMethod()`` which doesn't definee `$quz`. Commits ------- 1f5d8b6 [Debug] Trigger a deprecation for new parameters not defined in sub classes
Thank you, you've made a significant part (most? 😅) of this PR :) |
I'm not sure the way #28316 is implemented is the best so here is an alternative.
Instead of counting on a call from the child method, it uses the
DebugClassLoader
and@param
annotations. If a@param
annotation is used on a parent but is then not actually implemented in the child class, a deprecation will be thrown.Example:
A deprecation will be triggered because
SubClassWithAnnotatedParameters::quzMethod()
which doesn't definee$quz
.