Jump to content

access to the target of an attribute


Go to solution Solved by kicken,

Recommended Posts

 

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 by rick645
Link to comment
https://forums.phpfreaks.com/topic/317388-access-to-the-target-of-an-attribute/
Share on other sites

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 by rick645

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.

 

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 by rick645
  • Solution
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. 

 

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.

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 by rick645
This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.