Hacker News new | past | comments | ask | show | jobs | submit login

> All types are allowed, except void and callable

Urgh. It baffles me that 10 years after their introduction, anonymous functions (closures) remain useless when assigned to instance properties.

    class Foo {
        public $var;
    }
    $foo = new Foo();
    $foo->bar = function() { echo "Hello World\n"; };
    $foo->bar();
    Uncaught Error: Call to undefined method Foo::bar()
Callables work perfectly fine when assigned to standalone variables or array members: e.g. $foo[0](); But they become nonfunctional when assigned to instance properties. I understand that using closures as instance properties would make them hard to distinguish from methods, but blurring that distinction is just so damn useful in JavaScript!



You can invoke an anonymous function assigned to an instance property using `__invoke()`:

    class Foo {
        public $var;
    }
    $foo = new Foo();
    $foo->bar = function() { echo "Hello World\n"; };
    $foo->bar->__invoke();
Not pretty but that's how I've always done it.


Certainly prettier than using call_user_func($foo->bar), so that's something.


even better, you can surround the class and method reference in parentheses and call normally.

Example:

    $c = new stdClass;
    $c->test = function() { return 'hello world'; };
    echo ($c->test)();


It's less obvious though, you need to know what's happening and why. Likely not a problem for somebody writing a lot of JS, but I rarely see similar constructs in PHP code.


I guess it's a little less known but you also have to use the same technique to immediately invoke a method on a constructed object, eg.

    $response = (new Response())->handle ();
So it's not completely alien in PHP.


That's true, and probably depends on the code base.

I don't know how these patterns develop - it's very common in JS, but somewhat rare in PHP. Maybe it has to do with the average level of the programmer in each? Or jQuery's noConflict() helped it along with everybody starting with (function($) {})(jQuery), thus integrating IIFE into their active repertoire.

I don't remember (and haven't found in quickly searching) PSR saying anything about that, but that could explain a difference in usage, too.


Most PHP codebases simply don't have much use for IIFE's. A well-maintained project will be neatly organized into namespaces and classes, and undefined variables don't automatically become global. Meanwhile, PSR-1 says that a file that defines classes and/or functions should not have any side effect. So you don't have to worry about accidentally interacting with other scopes.

Anonymous functions and classes are being used more and more, but PHP isn't fundamentally event-driven like JS so there's less need to hand them out like candy and nest them several levels deep. Most of the closures I do use on a daily basis are callback functions to things like array_filter() and preg_replace_callback(), not event handlers like every jQuery code ever written.


I think it's well known by most developers using PHP. You can do the same to call a function on a newly created object.


You can also use Closure::bind / Closure::bindTo - see https://www.php.net/manual/en/closure.bind.php

<?php trait MetaTrait {

    private $methods = array();

    public function addMethod($methodName, $methodCallable)
    {
        if (!is_callable($methodCallable)) {
            throw new InvalidArgumentException('Second param must be callable');
        }
        $this->methods[$methodName] = Closure::bind($methodCallable, $this, get_class());
    }

    public function __call($methodName, array $args)
    {
        if (isset($this->methods[$methodName])) {
            return call_user_func_array($this->methods[$methodName], $args);
        }

        throw RunTimeException('There is no method with the given name to call');
    }
} ?>

test.php <?php require 'MetaTrait.php';

class HackThursday { use MetaTrait;

    private $dayOfWeek = 'Thursday';
}

$test = new HackThursday(); $test->addMethod('when', function () { return $this->dayOfWeek; });

echo $test->when();


They're not nonfunctional:

  ($foo->bar)();
Methods and properties are (perhaps regrettably) separate namespaces in PHP.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: