3

Is it possible to store a function in PHP object's properties like this:

class testing {
    public $testvars;
    function __construct(){
        $this->testvars = function(){
            return "Test String";
        };
    }
}

If it's possible, how do you call it?

I have been trying to call it like this:

$main = new testing();
$main->testvars();

But it throws an error:

Fatal error: Call to undefined method testing::testvars()
Sergey Telshevsky
  • 12,077
  • 6
  • 55
  • 78
Ikhsan Bahar
  • 154
  • 1
  • 1
  • 14

3 Answers3

2

Try to call like

$this->testvars();

Considering that you are calling this function in the same class.And if you are calling this in another class you need to add this _call() function

public function __call($method, $args) {
   if(isset($this->$method) && is_callable($this->$method)) {
       return call_user_func_array(
           $this->$method, 
           $args
       );
   }
}

to your new class and you can call it as

$main->testvars();
GautamD31
  • 28,552
  • 10
  • 64
  • 85
  • how could it be possible outside the class? – Royal Bg Jul 21 '14 at 06:18
  • 1
    thank you Gautam3164, it work like a charm.. – Ikhsan Bahar Jul 21 '14 at 06:39
  • @Forkiki good question too :-) – GautamD31 Jul 21 '14 at 06:40
  • Question is why to store a closure if you wan't to access it afterwards like a real method of the class instance. Why not just write out the method then? – TiMESPLiNTER Jul 21 '14 at 06:43
  • @TiMESPLiNTER nice point but we don't know why the OP needed it.And yes your point is good thing if she need it like you said – GautamD31 Jul 21 '14 at 06:44
  • I actually want to create a framework with different writing methods, for example, there is an assumption like "if($condition) {return true;}", I want to change it into "$Class->if($condition); $Class->returnif();", the problem is we cannot create a function with the name "if()", that's why I have to generate a function with the name "if()" via a property name – Ikhsan Bahar Jul 21 '14 at 08:25
1

The real problem is: yes, PHP syntax has lack of support fur such situation. Neither {..} nor (..) may help you. The only way to access the property (without __call() magic) is:

class testing {
    public $testvars;
    function __construct(){
        $this->testvars = function(){
            return "Test String";
        };
    }
}

$obj = new testing();

echo call_user_func_array($obj->testvars, []);

So to pass your callback into call_user_func_array(). Note big difference with passing of [$obj, 'testvars'] (which won't work here, obviously) - since your property contains a callback, but not class contains such method. You may also use call_user_func() of course.

As for syntax support, there is an RFC which is proposed by Nikita Popov and which will allow you to resolve the issue with syntax only - so no additional function calls would be needed (Fortunately, that RFC was accepted and has real chances to be implemented in newer PHP versions).

Alma Do
  • 37,009
  • 9
  • 76
  • 105
  • this solution works. I never heard of `call_user_func()` before. Thank you for pointing it out –  Jul 21 '14 at 06:28
  • So PHP searches only for valid member methods from object context instead of callables? +1 for the answer – Royal Bg Jul 21 '14 at 06:29
  • The answer depends of what are you meaning with "searches". With `->` syntax? Yes. It's method de-reference syntax and PHP will search within current scope for _method_. That, however, may be "tweaked" for arrays, for example, but not for such situation – Alma Do Jul 21 '14 at 06:30
  • Wow. Then why is the same solution needed for static properties. For example if you assign ot `self::$x` a closure. Then PHP should be aware of `Test::$x()` is not a method (to be honest, the error is different - function name must be a string). Shouldn't be all the same as $x() from procedural context? – Royal Bg Jul 21 '14 at 06:35
  • No, it is almost same. PHP won't be aware if it's method or property which you're trying to access (because of syntax, yes). Internally, btw, static methods and usual methods are almost same in byte-code, the difference is just flag (sort of). – Alma Do Jul 21 '14 at 06:37
  • The idea behing my comment was that I guess PHP is aware that `$x = function () { };` is callable after `echo $x()` because of the `$` identifier, which is also present in static fields. PHP could mess up the syntax for `$this->property()` because will never search for `property`, but in `self::$property()` it's pretty clear you are trying to access a property which is assigned to callable, isn't it? And the error is different, not that you are trying to access undefined function/method, but that function must be a string – Royal Bg Jul 21 '14 at 06:40
  • No, for PHP, `self::$property()` is an attempt to access static method with name "$property" (rule for parsing static calls). Since in _current_ context your `$property` isn't defined, it's empty and you see that error. – Alma Do Jul 21 '14 at 06:42
  • Nice to know that, thank you. I was really confused about it. For `$obj->property()` I am OK for this, because a normal human being will also confuse whether it's a method or property, but for `Class::$property()` it should be very clear, too bad it's not for the current PHP parser. – Royal Bg Jul 21 '14 at 06:44
  • There are many mysterious things inside PHP parser. Once you'll open that can of magic, you'll never forget. – Alma Do Jul 21 '14 at 06:45
0

You have to call your closure using call_user_func() or call_user_func_array().

So you can do the following:

$testing = new testing();
echo call_user_func($testing->testvars);

To call your closure outside of the class itself.

TiMESPLiNTER
  • 5,741
  • 2
  • 28
  • 64