1

The following PHP code results in an error: unexpected T_FUNCTION on the line starting with "say". I'm using PHP version 5.3.6 so lambdas should be supported, but it's not working. I don't know if the "use" clause is valid in this context either, but removing it does not resolve the problem. Is something wrong with my syntax? Note: $this->backend is defined in the constructor as $this->backend = fopen("bar.txt","w+");

class Foo
{
  private $backend;
  private $commands = array(
        0 => array(
            "say" => function($msg) use($this->backend) { fwrite($this->backend,$msg); }
            )
        );
}
Chris Browne
  • 1,582
  • 3
  • 15
  • 33

3 Answers3

4

Specific to PHP 5.3.x

First off, it's not possible to assign lambdas as default property values (lambdas are not considered a constant expression). So it is not possible to make that assignment directly; you would need to do it inside the constructor.

Secondly, in PHP 5.3.x you cannot use $this inside a lambda. The typical workaround is to make a copy of $this and capture that, as in:

$that = $this;
$func = function() use($that) { ... };

However this way it's not possible to access non-public members of $that from inside the lambda at all, so the technique cannot be used directly in your case.

What you should probably do is store $this->backend in a local variable inside the constructor and use that variable inside the lambda. Both the store and the capture can be done by value or by reference, depending on if you want any modifications to propagate outside the lambda and the possibility that the value of $this->backend may change before the lambda is invoked:

 public function __construct() {
    $backend = $this->backend;
    $this->commands = array(
        'say' => function($msg) use($backend) { fwrite($backend, $msg); }
    );
 }

Later PHP versions

Starting from PHP 5.4.0 you can implicitly use $this inside a lambda defined within a class method:

 public function __construct() {
    $this->commands = array(
        'say' => function($msg) { fwrite($this->backend, $msg); }
    );
 }

The restriction that lambdas cannot be assigned as default property values still stands.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • my version of PHP isn't allowing the array() syntax in the constructor, but does allow `$this->commands[0]["say"] = function($msg) use($backend) { ... }`, otherwise exactly as you wrote. I'm prepared to accept this answer pending the addition of this information. – Chris Browne Feb 03 '13 at 13:33
  • @ChrisBrowne: That's... not possible. What exactly is the array() syntax that fails? – Jon Feb 03 '13 at 13:35
  • the syntax `$this->commands = array( 0 => array("say" => function($msg) { ... }));` has the same 'unexpected T_FUNCTION' error as before – Chris Browne Feb 03 '13 at 13:36
  • @ChrisBrowne: But it [works as given](http://codepad.viper-7.com/hHOQEu) on e.g. 5.3.10. I 'm not 101% sure that nothing was different in 5.3.6 but pretty close up there. Are you using the same code? – Jon Feb 03 '13 at 14:12
  • ok, I'll accept then since it's probably a bug elsewhere in my code and I've moved on to bigger and better things so don't really want to investigate further; thanks :) – Chris Browne Feb 03 '13 at 15:50
0

The problem is

  use($this->backend)

$this doesn't exist yet in your class blueprint, so you absolutely can't specify it as this point.

What you're trying to do may be impossible to do inside an anonymous function, as it's not a member of the class as such, and hence doesn't get the $this variable.

You may have to do this in a proper member function of Foo, or pass $this as a parameter.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • As I said in the original question, removing "use($this->backend)" doesn't fix the error. Also removing the fwrite() call so that $this is never mentioned in the function does not fix the error. Thanks for your help, but I'm more concerned about the immediate problem of getting the lambda to work at all right now. – Chris Browne Feb 03 '13 at 13:01
  • @Chris oh, I misunderstood, sorry. – Pekka Feb 03 '13 at 13:03
  • no problem, like I said thanks for the point about $this, I've refactored that particular part of it to remove the reference to $this, but would still like to get rid of the pesky "unexpected T_FUNCTION" error first and foremost :) – Chris Browne Feb 03 '13 at 13:04
  • @Chris Hmmm, this *could* mean it's not possible to add anonymous functions as properties in the class blueprint. It looks very much like it. Let's wait for an expert opinion though, I don't know for sure... you could try assigning it in the constructor, I bet that'll work straight away – Pekka Feb 03 '13 at 13:07
  • @Pekka웃 http://stackoverflow.com/a/4000540/1283847 True for lambda functions too, anyway internally they are instances of `Closure` class. – Leri Feb 03 '13 at 13:25
  • fair enough; the problem is not solved simply by moving the assignment into the constructor, but changing it to an assignment into the $commands[0]["say"] variable rather than using the array() syntax works fine. – Chris Browne Feb 03 '13 at 13:27
0

You cannot define properties in classes directly from variables or as lambda;

// these are incorrect
private $foo = $bar
private $callback = function() ...

// correct
define("BAR", "The bar!");

class A {
    private $foo = BAR;
    private $commands = array();
    ...
    public function __construct() {
        $this->commands[0] = function() ...
Kerem
  • 11,377
  • 5
  • 59
  • 58