Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[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

Merged
merged 1 commit into from
Sep 21, 2018

Conversation

GuilhemN
Copy link
Contributor

@GuilhemN GuilhemN commented Aug 31, 2018

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:

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 */)
    {
    }
}
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.

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])) {
Copy link
Contributor Author

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.

@nicolas-grekas nicolas-grekas added this to the next milestone Aug 31, 2018
@nicolas-grekas
Copy link
Member

We should try to enable DebugClassLoader using the phpunit bridge and see how it goes!

@GuilhemN
Copy link
Contributor Author

GuilhemN commented Aug 31, 2018

@nicolas-grekas imo we can enable it either by updating the bridge and adding an SYMFONY_CLASS_DEBUG_LOADER env checked in its bootstrap.php or by having an autoloader dedicated to tests at the root of the symfony repository.

In both cases, it will require a consequent work to fix all deprecations (using php 7.1, I already have 2x: The "Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerForV6" class extends "PHPUnit\Framework\BaseTestListener" that is deprecated Use TestListenerDefaultImplementation trait instead., I'm not sure we can fix it without a new class). So 👍 for enabling it but I'd say in another PR 😄

@GuilhemN GuilhemN force-pushed the newparams branch 2 times, most recently from 7fd5331 to 57d935a Compare August 31, 2018 15:46
@nicolas-grekas
Copy link
Member

Ok works for me :)

@nicolas-grekas nicolas-grekas changed the title Trigger a deprecation for new parameters not defined in sub classes [Debug] Trigger a deprecation for new parameters not defined in sub classes Sep 2, 2018
@nicolas-grekas nicolas-grekas force-pushed the newparams branch 2 times, most recently from 623ebe7 to f69ec6f Compare September 8, 2018 22:24
@nicolas-grekas
Copy link
Member

nicolas-grekas commented Sep 8, 2018

@GuilhemN FYI I push-forced on your fork after squashing the CS commit. See also the 2nd commit I added: it enables DebugClassLoader from the PhpUnitBridge and it fixes a few issues found while doing so.

@@ -11,6 +11,8 @@

namespace Symfony\Component\Debug;

use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -984,8 +984,6 @@ public function setCache(array $options)
* @return $this
*
* @see http://tools.ietf.org/html/rfc2616#section-10.3.5
*
* @final
Copy link
Member

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

Copy link
Member

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?)

Copy link
Contributor Author

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

@GuilhemN
Copy link
Contributor Author

GuilhemN commented Sep 8, 2018

👍 thanks for doing these changes, I hope your second commit will help symfony keep a clean codebase :)

Copy link
Member

@nicolas-grekas nicolas-grekas left a 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.

@nicolas-grekas
Copy link
Member

phpunit-bridge part split in #28412

self::$finalMethods[$name] = array();
self::$internalMethods[$name] = array();
self::$annotatedParameters[$name] = array();
foreach ($parentAndTraits as $use) {
Copy link
Contributor Author

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.

Copy link
Member

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

Copy link
Contributor Author

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()) {
Copy link
Contributor Author

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.

Copy link
Member

@nicolas-grekas nicolas-grekas Sep 9, 2018

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

Copy link
Contributor Author

@GuilhemN GuilhemN Sep 12, 2018

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.

nicolas-grekas added a commit that referenced this pull request Sep 18, 2018
…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(
Copy link
Member

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

@nicolas-grekas
Copy link
Member

Could you please rebase (+squash) while fixing the small comment above to trigger tests?
There are some failures we need to take care of.

@nicolas-grekas nicolas-grekas force-pushed the newparams branch 2 times, most recently from 7cef7f2 to c03d5a1 Compare September 21, 2018 15:50
@nicolas-grekas
Copy link
Member

Thank you @GuilhemN.

@nicolas-grekas nicolas-grekas merged commit 1f5d8b6 into symfony:master Sep 21, 2018
nicolas-grekas added a commit that referenced this pull request Sep 21, 2018
…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
@GuilhemN GuilhemN deleted the newparams branch September 21, 2018 19:40
@GuilhemN
Copy link
Contributor Author

GuilhemN commented Sep 21, 2018

Thank you, you've made a significant part (most? 😅) of this PR :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants