rick645 Posted October 21, 2023 Share Posted October 21, 2023 (edited) tree ├── test1.php ├── test2.php ├── test3.php └── x.php cat test1.php <?php #[Attr()] class Cls { function method() {} } cat test2.php <?php #[Attr($this)] class Cls { function method() {} } cat test3.php <?php #[Attr(self)] class Cls { function method() {} } cat x.php <?php #[Attribute(Attribute::TARGET_CLASS)] class Attr { function __construct(Cls $cls = null) { $cls ? $cls->method() : Cls::method() ; } } require $argv[1]; $reflection = new ReflectionObject(new Cls); $attributes = $reflection->getAttributes( Attr::class ); foreach ($attributes as $attribute) { var_dump( $attribute->newInstance(), ); } In evidence (the targets) grep -F '#[Attr(' * test1.php:#[Attr()] test2.php:#[Attr($this)] test3.php:#[Attr(self)] The problems php x.php test1.php PHP Fatal error: Uncaught Error: Non-static method Cls::method() cannot be called statically in x.php:8 php x.php test2.php PHP Fatal error: Constant expression contains invalid operations in test2.php on line 4 php x.php test3.php PHP Fatal error: Uncaught Error: Undefined constant "self" in x.php:22 Solution? Edited October 21, 2023 by rick645 Quote Link to comment Share on other sites More sharing options...
rick645 Posted October 21, 2023 Author Share Posted October 21, 2023 (edited) Some improvements of compressibility tree ├── test1.php ├── test2.php └── x.php cat test1.php <?php #[Attr(target: $this)] class Target {} cat test2.php <?php #[Attr(target: self)] class Target {} cat x.php <?php #[Attribute(Attribute::TARGET_CLASS)] class Attr { function __construct(Target $target) { var_dump( $target ); } } require $argv[1]; $reflection = new ReflectionObject( new Target ); $attributes = $reflection->getAttributes( Attr::class ); foreach ($attributes as $attribute) { var_dump( $attribute->newInstance(), ); } grep -F 'target:' * test1.php:#[Attr(target: $this)] test2.php:#[Attr(target: self)] php x.php test1.php PHP Fatal error: Constant expression contains invalid operations in test1.php on line 4 php x.php test2.php PHP Fatal error: Uncaught Error: Undefined constant "self" in x.php:23 Edited October 21, 2023 by rick645 Quote Link to comment Share on other sites More sharing options...
requinix Posted October 21, 2023 Share Posted October 21, 2023 And a description of what's going on here would be...? Quote Link to comment Share on other sites More sharing options...
kicken Posted October 21, 2023 Share Posted October 21, 2023 I think you might be misunderstanding the purpose of attributes. It's not clear what you're trying to do though. If you need to access the instance of an object tagged with an attribute from within the attribute, you need to pass it in after the fact by calling some method on the attribute object. For example: <?php interface Target { public function something(); } #[Attribute] class Attr { public function doSomething(Target $target){ echo "Calling something method on ", get_class($target), PHP_EOL; $target->something(); } } #[Attr] class Target1 implements Target { public function something(){ echo "Did something in test 1 target.", PHP_EOL; } } #[Attr] class Target2 implements Target { public function something(){ echo "Did something in test 2 target.", PHP_EOL; } } if (class_exists($argv[1])){ $target=new $argv[1](); $reflection = new ReflectionObject($target); $attributes = $reflection->getAttributes(Attr::class); foreach ($attributes as $attribute) { $attr=$attribute->newInstance(); $attr->doSomething($target); } } else { echo 'No such class', PHP_EOL; } You'd get better help if you explain what you are trying to do and why, rather than just paste some code with a vague description. Quote Link to comment Share on other sites More sharing options...
rick645 Posted October 23, 2023 Author Share Posted October 23, 2023 (edited) I would like the use of the $target variable to be more limited. Here for example $attr->doSomething($target) In practice I would like the Attr class, from its interior, could automatically go back to the Target* class (or rather, to the instance), without passing it to the dosomething() method: maybe only to the construct, calling through the method newInstance() I had tried it test1.php:#[Attr(target: $this)] test2.php:#[Attr(target: self)] Edited October 23, 2023 by rick645 Quote Link to comment Share on other sites More sharing options...
Solution kicken Posted October 23, 2023 Solution Share Posted October 23, 2023 19 minutes ago, rick645 said: In practice I would like the Attr class, from its interior, could automatically go back to the Target* class (or rather, to the instance), This is where the misunderstanding of what attributes are and are for seems to come in. Attributes apply to the class itself. The only way to make a connection between a specific instance of a class and that classes attributes is when you use reflection on the instance to look up it's class and associated attributes. This process only works one way: instance -> class -> attributes. You cannot go backwards the other way: attribute -> class -> instance. Quote Link to comment Share on other sites More sharing options...
requinix Posted October 23, 2023 Share Posted October 23, 2023 If you want a distinction between $this (use the instance) and self (use the class statically) then create an enum with cases for instance vs. static, and take that enum as the argument to your attribute. But ultimately, the caring about the instance/class needs to happen by whatever code is reading the attribute. As in, you must necessarily already have code that says "for this particular class, find me the attributes" - so reuse that information. Quote Link to comment Share on other sites More sharing options...
rick645 Posted October 24, 2023 Author Share Posted October 24, 2023 (edited) However too many lines of code to access an attribute. In the future they should invent simpler things. Examples CLASS[.PROPERTY|METHOD].string|int:ATTRIBUTE_KEY->... CLASS[.PROPERTY|METHOD].string|int:ATTRIBUTE_KEY::... MyClass.0->method(); MyClass.my_attrib_name->... MyClass.1::CONST MyClass.2::staticMethod(); $instance.0->method(); $instance.my_attrib_name->... $instance.1::CONST $instance.2::staticMethod(); $instance.myProperty.0->... $instance.myProperty.my_name->... $instance.myProperty.1::... $instance.myMethod().0->... $instance.myMethod().my_name->... $instance.myMethod().1::... Someone should propose this on RFCs. Edited October 24, 2023 by rick645 Quote Link to comment Share on other sites More sharing options...
rick645 Posted October 24, 2023 Author Share Posted October 24, 2023 Sorry, the point "." It is already used as a concatenation operator, therefore to example they can be used => CLASS[=>PROPERTY|METHOD|CONST]=>string|int:ATTRIBUTE_KEY->... CLASS[=>PROPERTY|METHOD|CONST]=>string|int:ATTRIBUTE_KEY::... Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.