-
Notifications
You must be signed in to change notification settings - Fork 7.9k
ext/reflection: add getLine / getFileName / isUserDefined to reflection attribute #13889
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
Open
joelwurtz
wants to merge
1
commit into
php:master
Choose a base branch
from
joelwurtz:feat/reflect-attribute-filename
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
--TEST-- | ||
ReflectionAttribute getFileName | ||
--FILE-- | ||
<?php | ||
#[Attribute] | ||
class A {} | ||
|
||
class Foo { | ||
#[A] | ||
public function bar() {} | ||
} | ||
|
||
$rm = new ReflectionMethod(Foo::class, "bar"); | ||
$attribute = $rm->getAttributes()[0]; | ||
|
||
if ($attribute->getFileName() === __FILE__) { | ||
echo "OK"; | ||
} else { | ||
echo "FAIL"; | ||
} | ||
|
||
?> | ||
--EXPECT-- | ||
OK |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--TEST-- | ||
ReflectionAttribute getLines | ||
--FILE-- | ||
<?php | ||
#[Attribute] | ||
class A {} | ||
|
||
class Foo { | ||
#[A] | ||
public function bar() {} | ||
} | ||
|
||
$rm = new ReflectionMethod(Foo::class, "bar"); | ||
$attribute = $rm->getAttributes()[0]; | ||
|
||
var_dump($rm->getStartLine()); | ||
var_dump($attribute->getLine()); | ||
|
||
?> | ||
--EXPECT-- | ||
int(7) | ||
int(6) |
20 changes: 20 additions & 0 deletions
20
ext/reflection/tests/ReflectionAttribute_isUserDefined.phpt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
--TEST-- | ||
ReflectionAttribute isUserDefined | ||
--FILE-- | ||
<?php | ||
#[Attribute] | ||
class A {} | ||
|
||
class Foo { | ||
#[A] | ||
public function bar() {} | ||
} | ||
|
||
$rm = new ReflectionMethod(Foo::class, "bar"); | ||
$attribute = $rm->getAttributes()[0]; | ||
|
||
var_dump($attribute->isUserDefined()); | ||
|
||
?> | ||
--EXPECT-- | ||
bool(true) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Actually, I'm a bit confused by the intention here. Does this check whether the attribute class is internal, or whether the target is internal? It currently does the latter, but that doesn't seem super useful?
Uh oh!
There was an error while loading. Please reload this page.
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 intention is more : does the attribute (the instance not the class) as been defined (written) in user land code (wether it's a method / parameter / class / etc ...),
If it's an attribute from user land on an user land code it should return true
If it's an attribute from php core on an user land code it should return true
If it's an attribute from php core on php core it should return false
If it's an attribute from user land code on php core it should return false (but i don't think this use case is possible)
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.
Can you clarify why this matters? I understand that internal attributes can have additional validation without instanciation. But why does it matter whether the attrbute is placed on a user or internal target?
Uh oh!
There was an error while loading. Please reload this page.
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 is mainly if some library that do error handling (like https://github.com/symfony/error-handler by example) want to provide a generic way to pin point those error, they could then only do that when they detect that the attribute has been writed by the user
But i'm wondering if PHP internal class may have internal attributes attached to their method or class (now or in the future) defined ? I know there is pre defined attributes by PHP but not sure if there are used in internal methods or if an extension can declare them using C code ?
If not then this is useless
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.
Yes, internal attributes can be attached to internal classes, but instantiating them should never error. If it does error, that would be a bug in core/the extension itself. I'm still confused about when and why exactly Symfony error handler would need this information.
Can you provide a concrete example? Moreover, whether the target is internal would already be known, by looking at the reflection of the class/method itself.
Uh oh!
There was an error while loading. Please reload this page.
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.
As an example we could, in a generic error handler, do the following interface :
When the error handler catch an exception with this interface it may do special things like show the exception (like before) and add a special text (or HTML in web context) to the user to show which attributes this exception concern (it could even show the portion of code in web context).
Library would only have to implement this interface in their exception and the error handler would do the rest
Having the
isUserDefined()
method would allow this generic handler to be sure that the reflection attribute given has been written in a PHP file and does not originate from the core (in the last case there is no point showing something since it's not written in a PHP file and so it's not fixable by the user)This method may not be necessary if the interface look like this :
In this case we could determine if it's user defined given the specific target.
The disadvantage, is that user implementing this interface would need to track every Attribute with their Target, and in some cases it may involved passing those 2 values a lot of times which is cumbersome.
But maybe the
isUserDefined()
method is not the best approach. Wouldn't it be better if instead we have thisgetTarget()
method inside theReflectionAttribute
class ?So we could have the target of the attribute without having to keep track of it in PHP code ?
There is already a
getTarget()
method that returns anint
, there could be agetDeclaringTarget()
that returns\ReflectionClass | \ReflectionMethod |\ReflectionFunction | \ReflectionParameter | \ReflectionProperty