Skip to content
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

PHP 7.2 Magic autoload deprecation #540

Merged
merged 19 commits into from
Dec 6, 2017
Merged

Conversation

@wimg wimg added this to the 8.1.0 milestone Dec 1, 2017
@wimg wimg requested a review from jrfnl December 1, 2017 17:42
Copy link
Member

@jrfnl jrfnl left a comment

Choose a reason for hiding this comment

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

Looks good. I'm looking forward to merging this as the last PHP 7.2 deprecation 🎉!

I'm wondering if a little more protection against false positives is warranted.
As far as I know, the __autoload function will only be recognized as an autoloader when defined in the global namespace, i.e. not in a namespaced file or when a method in a class is called __autoload.
Though I'm starting to doubt myself after seeing your test case.

The sniff as it is now, would in those cases also throw warnings.
If a change is needed for this, you can probably use these existing utility functions to execute the needed checks:

  • validDirectScope() - to determine if the function $stackPtr is defined in a T_CLASS, T_ANON_CLASS, T_INTERFACE or T_TRAIT.
  • determineNamespace() - to determine whether the function $stackPtr is defined in a namespaced file.

If this is changed, the unit tests would also need to reflect this.

phpcs.xml.dist Outdated
@@ -66,6 +66,8 @@
<rule ref="Generic.Commenting.DocComment">
<!-- Having a @see or @internal tag before the @param tags is fine. -->
<exclude name="Generic.Commenting.DocComment.ParamNotFirst"/>
<!-- We prefer seeing nicely looking docblock comments -->
<exclude name="Generic.Commenting.DocComment.TagValueIndent"/>
Copy link
Member

Choose a reason for hiding this comment

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

  1. This should be a separate PR.
  2. What are you trying to solve here ? Could you give a code example ?

Copy link
Member Author

Choose a reason for hiding this comment

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

return;
}

$this->addMessage($phpcsFile, 'Use of __autoload() function is deprecated since PHP 7.2', $stackPtr, false);
Copy link
Member

Choose a reason for hiding this comment

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

As there is no error/warning toggle needed at this moment, why not call the $phpcsFile->addWarning() method directly ?

Copy link
Member Author

Choose a reason for hiding this comment

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

100% true :-)

}

class foo {
function __autoload($someclass) {
Copy link
Member

Choose a reason for hiding this comment

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

Are you sure this code works as an autoloader ? I always though the __autoload() function had to be defined in the global namespace ?

@jrfnl
Copy link
Member

jrfnl commented Dec 1, 2017

Just re-read the RFC: looks like my initial remark about it only applying to global functions was correct:

Proposed action: A deprecation notice is thrown when a global function with name __autoload() is encountered during compilation.

Maybe we should file a bug regarding the migration guide ? It is called a method there, while it should be called function.

@wimg
Copy link
Member Author

wimg commented Dec 2, 2017

So the question is : what do we do about declarations of it outside the global namespace ?
The new code will generate a warning, regardless of the location...

@jrfnl
Copy link
Member

jrfnl commented Dec 2, 2017

So the question is : what do we do about declarations of it outside the global namespace ?
The new code will generate a warning, regardless of the location...

I'm not sure I understand what you are asking.
Just looking at the code, I would expect it to now only generate a warning when the function declaration is found in the global namespace and to no longer throw warnings when it's either namespaced or in a valid direct scope....

For that matter: I'm missing a test for a namespaced function declaration, both scoped and non-scoped namespace.

Let me check out the branch and test it, maybe that'll help me understand what you mean.

return;
}

if ($this->validDirectScope($phpcsFile, $stackPtr, array('T_CLASS', 'T_ANON_CLASS', 'T_INTERFACE', 'T_TRAIT')) === true) {
Copy link
Member

@jrfnl jrfnl Dec 2, 2017

Choose a reason for hiding this comment

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

Ah! Found it. The ValidDirectScope() method expects the string tokens as keys in the array, so it can use the more efficient isset().

So it expects the array to be passed like this:

$excludeScopes = array(
	'T_CLASS'      => true,
	'T_ANON_CLASS' => true,
	'T_INTERFACE'  => true,
	'T_TRAIT'      => true,
	'T_NAMESPACE'  => true, // = Only scoped namespaces, non-scoped still needs to be checked in another way.
);

if ($this->validDirectScope($phpcsFile, $stackPtr, $excludedScopes) === true) {
	....

As $excludedScopes does not change between calls to the sniff, it should probably be declared as a private property of the sniff.

Also, the validDirectScope() method is quicker and simpler than the determineNamespace() method, so the order of the checks should probably be reversed for efficiency of the sniff.

Copy link
Member

@jrfnl jrfnl left a comment

Choose a reason for hiding this comment

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

Few more small remarks.

Regarding the build failure: this is to do with PHP 5.3 in combination with PHPCS < 2.4.0.

Traits aren't recognized as a separate token yet.
Interfaces are, but the tokens within the interface don't get the scoped condition correctly.

Considering it's such an old PHP and PHPCS version, I'd be happy to just bypass those unit tests for that particular combination.

array(self::TEST_FILE, 14),
array(self::TEST_FILE, 18),
array(self::TEST_FILE, 24),
array(self::TEST_FILE_NAMESPACED, 6),
Copy link
Member

Choose a reason for hiding this comment

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

These are all one line off -> 5, 10, 15, 20, 26

*
* @return void
*/
public function testIsNotAffected($testFile, $line)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe call it testNoFalsePositives() for consistency with all the other test files ?

*/
public function testIsDeprecated($line)
{
$file = $this->sniffFile(self::TEST_FILE, '7.1');
Copy link
Member

Choose a reason for hiding this comment

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

You could remove this first test in favour of an overal testNoViolationsInFileOnValidVersion() test for 7.1 checking the complete file (see other unit test files)

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point. Fixed in next commit.

class DeprecatedMagicAutoloadSniff extends Sniff
{
/**
* Scopes to exclude when testing using validDirectScope
Copy link
Member

Choose a reason for hiding this comment

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

This documentation is incorrect. The ValidDirectScope() method needs to actually look for these scopes. In the sniff code itself, no warning is then thrown if any of them are found.

Copy link
Member Author

Choose a reason for hiding this comment

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

Can you elaborate on this ?

Copy link
Member

Choose a reason for hiding this comment

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

When I read this comment, I'd think that those scopes are excluded when calling validDirectScope(), while in actual fact, you are looking for those scopes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah ok thanks ;-)

'T_TRAIT' => true,
'T_NAMESPACE' => true, // = Only scoped namespaces, non-scoped still needs to be checked in another way.
);

Copy link
Member

Choose a reason for hiding this comment

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

You seem to have trailing whitespace here which you may want to remove. Strange that the PHPCS run is not complaining about that.... hmm.... will need to look into that.

function __autoload($someclass) {
echo 'I am the autoloader in an anonymous class (which makes no sense) - I am deprecated from PHP 7.2 onwards';
}
});
Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: there should be a new line at the end of the file

function __autoload($someclass) {
echo 'I am the autoloader in an anonymous class (which makes no sense) - I am deprecated from PHP 7.2 onwards';
}
});
Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: there should be a new line at the end of the file

public function testIsNotAffected($testFile, $line, $isTrait)
{
if ($isTrait === true && self::$recognizesTraitsOrInterfaces === false) {
$this->markTestSkipped('Traits are not recognized on PHPCS < 2.4.0 in combination with PHP < 5.4');
Copy link
Member

Choose a reason for hiding this comment

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

Not a merge blocker, but just documenting this: the skip message is not entirely accurate as it also applies to interfaces where scope is not being recognized (yet).

array(self::TEST_FILE, 14, true),
array(self::TEST_FILE, 18, true),
array(self::TEST_FILE, 24, false),
array(self::TEST_FILE_NAMESPACED, 6, false),
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be line 5 ?

array(self::TEST_FILE, 18, true),
array(self::TEST_FILE, 24, false),
array(self::TEST_FILE_NAMESPACED, 6, false),
array(self::TEST_FILE_NAMESPACED, 11, false),
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be line 10 ?

@jrfnl jrfnl merged commit 04651f6 into master Dec 6, 2017
@jrfnl jrfnl deleted the magic-autoload-deprecations branch December 6, 2017 10:02
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.

2 participants