-
Notifications
You must be signed in to change notification settings - Fork 501
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
Do not report constructor unused parameter if class is an Attribute class #3776
Do not report constructor unused parameter if class is an Attribute class #3776
Conversation
There is a failing check but seems unrelated to the PR 🤔 |
Simply promoting the property should fix the error: [\Attribute]
class MyAttribute
{
public function __construct(public string $name) {}
} |
Thank you! |
Hi @ondrejmirtes , Just saw this and I really don't understand as this might hide real issues... the In fact the access to property shall indeed be done like @calebdw described, meaning it shall be a public property. Note to people using Reflection to access Attributes's constructor's parameters: To access attribute's values Reflection can be used with
|
@vdauchy You might access the attribute arguments through reflection with https://www.php.net/manual/en/reflectionattribute.getarguments.php which is what I think the author phpstan/phpstan#7165 is doing and that's why PHPStan reported false positives to them. |
Can we at least have an option to disable this please? This is a really strange change as @vdauchy outlined above. We seem to have adjusted PHPStan to disable a potentially useful warning based on the requirements of one user in phpstan/phpstan#7165. Their code would almost certainly be better adjusted to call The original example <?php
declare(strict_types=1);
namespace XX\XXX\Structs\Attribute;
use Attribute;
#[Attribute(Attribute::TARGET_PROPERTY)]
final class ArrayList
{
public function __construct(string $structName)
{}
}
class Ball
{
#[ArrayList('balablub')]
public array $colors = [];
}
class Example
{
public function readArgumentValue(): void
{
$reflection = new \ReflectionClass(Ball::class);
$reflectionProperties = $reflection->getProperties();
$reflectionProperty = $reflectionProperties[0];
$reflectionAttributes = $reflectionProperty->getAttributes();
$reflectionAttribute = $reflectionAttributes[0];
$reflectionArguments = $reflectionAttribute->getArguments();
$reflectionArgument = $reflectionArguments[0]; // balablub
echo $reflectionArgument;
}
}
(new Example()) -> readArgumentValue(); Yes, this works, and the pattern is alluded to in the manual. But there is also a very important caveat:
Hence I don't believe this pattern should be routinely used to access Attributes data, because despite <?php
declare(strict_types=1);
namespace XX\XXX\Structs\Attribute;
use Attribute;
#[Attribute(Attribute::TARGET_PROPERTY)]
final class ArrayList
{
public function __construct(string $structName)
{}
}
class Ball
{
// int being passed to string parameter
#[ArrayList(12345)]
public array $colors = [];
}
class Example
{
public function readArgumentValue(): void
{
$reflection = new \ReflectionClass(Ball::class);
$reflectionProperties = $reflection->getProperties();
$reflectionProperty = $reflectionProperties[0];
$reflectionAttributes = $reflectionProperty->getAttributes();
$reflectionAttribute = $reflectionAttributes[0];
$reflectionArguments = $reflectionAttribute->getArguments();
$reflectionArgument = $reflectionArguments[0]; // 12345
echo $reflectionArgument;
}
}
(new Example()) -> readArgumentValue(); How the example almost certainly should be written (note that this is also shorter!) <?php
declare(strict_types=1);
namespace XX\XXX\Structs\Attribute;
use Attribute;
#[Attribute(Attribute::TARGET_PROPERTY)]
final class ArrayList
{
public function __construct(public readonly string $structName)
{}
}
class Ball
{
#[ArrayList('balablub')]
public array $colors = [];
}
class Example
{
public function readArgumentValue(): void
{
$reflection = new \ReflectionClass(Ball::class);
$reflectionProperties = $reflection->getProperties();
$reflectionProperty = $reflectionProperties[0];
$reflectionAttributes = $reflectionProperty->getAttributes();
$reflectionAttribute = $reflectionAttributes[0];
echo $reflectionAttribute -> newInstance() -> structName;
}
}
(new Example()) -> readArgumentValue(); As it stands, we now have the potential for unused constructor parameters to be missed in any class that happens to be an As |
I don't think this is true outside of Attributes. Reflection doesn't have any concept of function call arguments, outside of Attributes. Sorry, I don't have any plans adding this back for attribute classes. It's too much of an edge case, I don't think it's worth it to pollute the configuration parameters or the documentation. |
When defining
Attribute
classes usually the constructor parameters are not used, as the values are retrieved using reflection.This PR modifies the
UnusedConstructorParametersRule
class so that unused constructor parameters are not reported if the class is anAttribute
class.Fixes phpstan/phpstan#7165