3

First excuse my english I'm not a native speaker and sorry if it looks rough, this is the first time that I post on this site. My problem is quite simple I think. Let's say, we have :

class A {

    function foo() {

        function bar ($arg){
            echo $this->baz, $arg;
        }

        bar("world !");

    }

    protected $baz = "Hello ";

}

$qux = new A;

$qux->foo();

In this example, "$this" obviously doesn't refer to my object "$qux".

How should I do to make it reffer to "$qux"?

As might be in JavaScript : bar.bind(this, "world !")

3
  • 2
    why you need to nest functions in php? It's bad practice Commented Nov 19, 2014 at 10:41
  • It's simply because I use the same code twice in this function. Commented Nov 19, 2014 at 11:31
  • then use closures as @georg suggested Commented Nov 19, 2014 at 11:40

4 Answers 4

2

PHP doesn't have nested functions, so in your example bar is essentially global. You can achieve what you want by using closures (=anonymous functions), which support binding as of PHP 5.4:

class A {
    function foo() {
        $bar = function($arg) {
            echo $this->baz, $arg;
        };
        $bar->bindTo($this);
        $bar("world !");
    }
    protected $baz = "Hello ";
}

$qux = new A;
$qux->foo();

UPD: however, bindTo($this) doesn't make much sense, because closures automatically inherit this from the context (again, in 5.4). So your example can be simply:

    function foo() {
        $bar = function($arg) {
            echo $this->baz, $arg;
        };
        $bar("world !");
    }

UPD2: for php 5.3- this seems to be only possible with an ugly hack like this:

class A {
    function foo() {
        $me = (object) get_object_vars($this);
        $bar = function($arg) use($me) {
            echo $me->baz, $arg;
        };
        $bar("world !");
    }
    protected $baz = "Hello ";
}

Here get_object_vars() is used to "publish" protected/private properties to make them accessible within the closure.

Sign up to request clarification or add additional context in comments.

8 Comments

PHP has nested functions, but is normally is not very wise to use them stackoverflow.com/questions/415969/…
@Asped: no. You can write a function inside another one, but that doesn't make it nested. Inner functions are global.
Ok so I've used closures but by using a variable instead of "$this". I have to consider PHP < 5.4 so I did it with "use". I don't realy know if it's the best practice.
@user3292788: yes, this seems to be the only way. Added a note to the answer.
I see but is there a way to pass it by reference ? How would it be if I want to modify the value ?
|
2

Actually, $this does refer to $qux when called in that context.

You can't use $this in contexts other than an object method, so if you took something like this:

function test() {
    echo $this->baz;
}

It wouldn't work, no matter what you do.

Comments

0

it is a little strange to to it this way, but if you use a function inside of a function, then of course some closuers are in effect. you can have a similar problem in javascript. I would suggest not to use them at all, but if for some reason you do not want to, then i would try sth like this (not tested):

class A {

    function foo() {

        $that = $this;
        function bar ($arg){
            echo $that->baz, $arg;
        }

        bar("world !");

    }

    protected $baz = "Hello ";

}

$qux = new A;

$qux->foo();

UPDATE if the nested function acts as a global function, then you coud pass your object as a parameter if you need to use it:

function foo() {

        function bar ($o,$arg){
            echo $o->baz, $arg;
        }

        bar($this,"world !");

    }

Comments

0

If I understand what you're trying to achieve, it could be like this:

<?php
class Foo {

  public $prop;

  public function __construct($prop) {
    $this->prop = $prop;
  }

  public function __call($name, $arguments) {
    if (!isset($this->$name)) {
      throw new InvalidArgumentException("No such property: $name");
    }

    if (! $this->{$name} instanceof Closure) {
      throw new InvalidArgumentException("{$name} is not a closure");
    }

    $c = $this->{$name}->bindTo($this);
    return $c(...$arguments);
  }
}

$f = new Foo("bar");
$f->bar = function ($arg) {
  print_r([$arg, $this->prop]);
};

$f->bar("A");
?>

That way you can essentially monkey-patch any function in a class and call it as if it was local, even including use of $this. Two limitations, however:

  • this seems pointless since Traits are available, except if you are doing adding really dynamically defined on a non-modifiable package
  • although the closure can access properties on $this it is still external to the object, so can only access public properties. Trying to access protected/private properties will fail.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.