2

I have some confusions! I've a simple class as given below

class MyClass {
    public $bar;
}

Then I made an instance

$cls = new MyClass;

Then I've assigned value to my public property $bar from outside of the class

$cls->bar='Bar';

Then I've added new public property $baz and assigned value to it from outside of the class

$cls->baz='Baz';

Then I've added a new public property $showBar and assigned value to it from outside of the class and this time the value is an anonymous function

$cls->showBar = function(){
    return $this->bar;
};

Then I've dumped the $cls using var_dump($cls); instance and output is

object(MyClass)[10]
  public 'bar' => string 'Bar' (length=3)
  public 'baz' => string 'Baz' (length=3)
  public 'showBar' => 
    object(Closure)[11]

Seems that all the public properties are available that I've added including the anonymous function and then I've done

echo $cls->bar; // Bar
echo $cls->baz; // Baz
echo $cls->showBar(); // error

The public property showbar is available in the class (the var_dump shows it) but when I call the function it says

Fatal error: Call to undefined method MyClass::showBar() in D:\xampp\htdocs\phpTutorialInfo\bind\bindtoCls.php on line 234

The question is : It's possible to add new properties after initialization (works fine with a scalar value) and also the showbar seems available then why can't Php recognize it and If it's because it's value is a an anonymous function then why it's available in the var_dump output including the function itself and why Php let me assign the value (anonymous function), it should have thrown an error when I was trying to assign the value of showbar property ? Is that possible at all ?

The Alpha
  • 143,660
  • 29
  • 287
  • 307
  • I think the way you're calling the showBar() function, it might not think of $this as being the object $cls. Did you get an actual error message? Posting it may help illuminate things. – murftown Jul 01 '13 at 19:42
  • possible duplicate of [Lambda Functions in PHP aren't Logical](http://stackoverflow.com/questions/2080248/lambda-functions-in-php-arent-logical) – outis Aug 04 '13 at 21:43

3 Answers3

4

You cannot call the function this way. That's because PHP allows to have variables an functions having the same name in a class. If you use the function operator () PHP will only look into the list of functions and don't look at variables that are closures.

As of PHP5.4 a solution could look like this:

class MyClass {

    public function __call($fname, $args) {
        // bind the `this` scope to use
        $cl = $this->{$fname}->bindTo($this);
        // call the function and pass args to it
        return call_user_func_array($cl, $args);
    }

}

Example:

$obj = new MyClass();
$obj->func = function() {
    echo 'We are in ' . get_class($this);
};

$obj->func(); // We are in MyClass

You can test this here

hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • `echo $cls->showBar->__invoke();` will not work as he's setting the closure and using `$this` when out of context, I believe the `__call` magic method may help. – Rob W Jul 01 '13 at 19:44
  • 1
    `bind` and `bindTo` is PHP 5.4+ only, and closures are PHP 5.3+. (just an fyI) – Rob W Jul 01 '13 at 19:49
  • yeah, I've seen this just a moment ago :) – hek2mgl Jul 01 '13 at 19:50
  • result is `Fatal error: Using $this when not in object context in D:\xampp\htdocs\phpTutorialInfo\bind\bindtoCls.php on line 237`. I'm using `Php 5.4`. – The Alpha Jul 01 '13 at 19:50
  • This `$cls->func = function() { return $this->bar; };` won't work and I'm asking for this, is that possible at all ? Pleas heck my question, I've used `$this`. – The Alpha Jul 01 '13 at 20:02
  • @RobW Thx for helping me out with debugging this.. ;) ... However, now when it is ready I'm not sure anymore that binding the this scope without having control over it may not wanted in most situations.. What do you say? – hek2mgl Jul 01 '13 at 20:03
  • Check out some of the comments on php.net: http://www.php.net/manual/en/closure.bindto.php – Rob W Jul 01 '13 at 20:12
  • I've checked it out already and this question is buzzing around my head since ages, check [this question](http://stackoverflow.com/questions/11503212/add-method-in-an-std-object-in-php) of mine. – The Alpha Jul 01 '13 at 20:17
  • @hek2mgl, Thanks for your effort and nice answer. – The Alpha Jul 01 '13 at 20:20
  • @SheikhHeera You are welcome. It's an interesting problem +1. (I had almost the same today ;) – hek2mgl Jul 01 '13 at 20:25
3

You cannot add a method dynamically in PHP. What you have done is adding a custom property, which is a function. But this does not makes it a method. To illustrate the difference, you can create a class, with a property & a method with the same name:

class A {
    public $test = 42;
    public test() { return 43; }
}

$a = new A;
$a->test === 42;
$a->test() === 43;
pozs
  • 34,608
  • 5
  • 57
  • 63
  • closures can be methods as a property, though. – Rob W Jul 01 '13 at 19:45
  • 2
    No, closures can be bound to an object, but that doesn't makes them methods, i.e. you cannot call them like `$object->closureAsProperty()` – pozs Jul 01 '13 at 19:48
2

You can use call_user_func. Example:

<?php
class MyClass {
    public $bar;
}
$cls = new MyClass;
$cls->bar='Bar';
$cls->baz='Baz';
$cls->showBar = function() use ($cls) {
    return $cls->bar;
};

echo call_user_func($cls->showBar); // Bar
?>

You may want to define the __call magic method so it may be possible to return $this->bar instead of passing $cls in the closure.

Rob W
  • 9,134
  • 1
  • 30
  • 50
  • This will work (I've already tested it) but `$this` is not applicable inside closure. I'm just trying to simulate `JavaScript`'s `prototype` if it's possible at all, but thanks for your answer. – The Alpha Jul 01 '13 at 19:48
  • The thing with this solution is ... you're kind of just "reinventing the wheel" when you just want to access `$cls->bar` directly; though that's just for this example. Your mileage may vary. – Rob W Jul 01 '13 at 19:50
  • I'm just trying to add methods after an object's initialization using `Closure`. – The Alpha Jul 01 '13 at 19:52