-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[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 |
|
|
||
| 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
| * | ||
| * @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
nicolas-grekas
left a comment
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
| } | ||
|
|
||
| // 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
| 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
DebugClassLoaderand@paramannotations. If a@paramannotation 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.