Add method in an std object in php
Asked Answered
R

5

29

Is it possible to add a method/function in this way, like

$arr = array(
    "nid"=> 20,
    "title" => "Something",
    "value" => "Something else",
    "my_method" => function($arg){....}
);

or maybe like this

$node = (object) $arr;
$node->my_method=function($arg){...};

and if it's possible then how can I use that function/method?

Reggy answered 16/7, 2012 at 11:22 Comment(0)
A
20

You cannot dynamically add a method to the stdClass and execute it in the normal fashion. However, there are a few things you can do.

In your first example, you're creating a closure. You can execute that closure by issuing the command:

$arr['my_method']('Argument')

You can create a stdClass object and assign a closure to one of its properties, but due to a syntax conflict, you cannot directly execute it. Instead, you would have to do something like:

$node = new stdClass();
$node->method = function($arg) { ... }
$func = $node->method;
$func('Argument');

Attempting

$node->method('Argument')

would generate an error, because no method "method" exists on a stdClass.

See this SO answer for some slick hackery using the magic method __call.

Ailanthus answered 9/7, 2013 at 1:50 Comment(2)
+1, It's done in other ways long ago, Someone edited the answer, see the date but thanks for your effort.Reggy
Whoops! I completely overlooked that. Thank you though.Ailanthus
C
37

This is now possible to achieve in PHP 7.1 with anonymous classes

$node = new class {
    public $property;

    public function myMethod($arg) { 
        ...
    }
};

// and access them,
$node->property;
$node->myMethod('arg');
Cloudy answered 20/9, 2017 at 15:2 Comment(3)
Nice one, I was mocking some data and this proved pretty helpful.Laughry
but does this add a new function to an already defined object?Cryogen
@Geomorillo, No, it does not add to object, you can "add function to class" with extends on (anonymous) class. It is php, it is not JavaScript. But on other answers you can see also unreadable solutions with __call.Dollar
A
20

You cannot dynamically add a method to the stdClass and execute it in the normal fashion. However, there are a few things you can do.

In your first example, you're creating a closure. You can execute that closure by issuing the command:

$arr['my_method']('Argument')

You can create a stdClass object and assign a closure to one of its properties, but due to a syntax conflict, you cannot directly execute it. Instead, you would have to do something like:

$node = new stdClass();
$node->method = function($arg) { ... }
$func = $node->method;
$func('Argument');

Attempting

$node->method('Argument')

would generate an error, because no method "method" exists on a stdClass.

See this SO answer for some slick hackery using the magic method __call.

Ailanthus answered 9/7, 2013 at 1:50 Comment(2)
+1, It's done in other ways long ago, Someone edited the answer, see the date but thanks for your effort.Reggy
Whoops! I completely overlooked that. Thank you though.Ailanthus
C
14

Since PHP 7 it is also possible to directly invoke an anonymous function property:

$obj = new stdClass;
$obj->printMessage = function($message) { echo $message . "\n"; };
echo ($obj->printMessage)('Hello World'); // Hello World

Here the expression $obj->printMessage results in the anonymous function which is then directly executed with the argument 'Hello World'. It is however necessary to put the function expression in paranetheses before invoking it so the following will still fail:

echo $obj->printMessage('Hello World'); 
// Fatal error: Uncaught Error: Call to undefined method stdClass::printMessage()
Carothers answered 13/7, 2019 at 15:36 Comment(0)
A
0

Another solution would be to create an anonymous class and proxy the call via the magic function __call, with arrow functions you can even keep reference to context variables:

 new Class ((new ReflectionClass("MyClass"))->getProperty("myProperty")) {
            public function __construct(ReflectionProperty $ref)
            {
                $this->setAccessible = fn($o) => $ref->setAccessible($o);
                $this->isInitialized = fn($o) => $ref->isInitialized($o);
                $this->getValue = fn($o) => $ref->getValue($o);
            }

            public function __call($name, $arguments)
            {
                $fn = $this->$name;
                return $fn(...$arguments);
            }

    }
Attrition answered 30/4, 2020 at 16:27 Comment(0)
U
0
class myclass {
function __call($method, $args) {
if (isset($this->$method)) {
$func = $this->$method;
return call_user_func_array($func, $args);
}
}
}
$obj = new myclass();
 $obj->method = function($var) { echo $var; };

$obj->method('a');

Or you can create defult class and use...

Unsaddle answered 21/7, 2021 at 14:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.