1. 19
  1.  

  2. 30

    This is just wrong. Did the author just skip the part of the documentation which shows this example?

    // Reset message
    $message = 'hello';
    
    // Inherit by-reference
    $example = function () use (&$message) {
        var_dump($message);
    };
    $example();
    
    // The changed value in the parent scope
    // is reflected inside the function call
    $message = 'world';
    $example();
    

    Yes, PHP Does Have Closures.

    (edit: if you’re unconvinced, here’s a small closure-based counter-generator and here’s a website you can paste it into. I’m no PHP fan but I worked with it for years and this kind of uninformed bagging serves nobody.)

    For what it’s worth, C++ lambdas are the same — they copy by default unless you specify you want a by reference capture, by prepending a &, just the same.

    1. 6

      Wellons usually makes a good point. I think he was blinded by PHP hate on this one.

      I think use is actually a little better than the JavaScript approach because A) an ordinary closure is a reference, but use lets us choose between value or reference, and B) in the long run, explicit is usually better than implicit.

      If someone’s closing over so many variables that it becomes a hardship to enumerate them in a use clause, they already have bigger problems. Combine the implicit JS approach with its liberal interpretation of what a valid program is, and it is just too easy to accidentally close over a variable there.

      1. 3

        I agree. I bristled at first when I hit this kind of closure declaration in C++, but soon found I appreciated declaring exactly what I care about and whether I wanted my own copy, as with any well-designed function.

        1. 1

          I happen to agree that explicitly declaring the variables to be used is better. I disagree that having to do so is “closing over” the environment.

          1. 5

            When all else fails, there’s Wikipedia:

            Joel Moses credits Landin with introducing the term closure to refer to a lambda expression whose open bindings (free variables) have been closed by (or bound in) the lexical environment, resulting in a closed expression, or closure.

            So a function value that uses variables defined in the enclosing scope is always a closure, regardless of whether the referencing has to be done manually or not.

            1. 1

              I disagree that having to do so is “closing over” the environment.

              If the only difference is whether you specify which variables are included, then we’re really splitting hairs. Whether the language automatically brings in all free variables or asks you to list them doesn’t make a difference: it’s binding free variables/closing open bindings – a closure. Given PHP’s laxity in variable declaration, one could argue this is the best way to do closures in the language.

        2. 6

          The author does mention that in the “references” section, although is quick to dismiss it.

          This entire article reads like “they didn’t do it in my favourite way, therefore it’s invalid!”. While I’m generally not especially impressed by most aspects of PHP I personally rather like the explicit closures. Implicit closing over variables can be problematic in many languages and generally I feel The Zen of Python got it right with “explicit is better than implicit”.

          A better article would at least address the motivations the PHP authors had for using these semantics instead of just dismissing it out of hand as “dumb”.

          1. 5

            “-1 incorrect”

            I would love for you to elaborate!

            1. 0

              By the way, that was not me that downvoted, even though I disagree!

              1. 1

                All good! Even if you did that’d be fine.

            2. 4

              Is that really a closure though? The $message parameter is actually an implicit argument to the function. The function is not closing over an environment, it is closing over a list of parameters that have implicit arguments from the environment, in addition to the regular explicit parameter list.

              These are function values, not closures.

              1. 5

                Imagine you could write use (&*) to list every variable – in what way would it substantively differ from your idea of closures? What’s an example?

                1. 3

                  The function is not closing over an environment

                  &$x means you want $x inside the function body to refer to the current environment. As an example:

                  function f($a) {
                    return array(
                      s => function($v) use (&$a) { $a = $v; },
                      g => function() use (&$a) { return $a; }
                    );
                  }
                  

                  would not work correctly if the environment was not being closed over.

                  1. 2

                    The only real difference I see from “true” closures is that it’s not automatic. I would hope that most languages with Real Closures don’t capture the entire lexical environment - they analyse the function body to do the same thing as PHP (edit: and C++), without requiring the user to specify which variables to capture. This thing about references is a red herring.

                    1. 2

                      I’ve not looked at the implementation details, but the ability to dynamically reference properties, i.e. with eval(),, suggests that “true” closures do capture the entire static environment. That is pretty much the definition of, and the etymology of, the term closure. “Closing over” a specific instance of an environment.

                      1. 2

                        That surely depends entirely on the language and capabilities of eval therein (Racket requires some hoop-jumping for eval to be able to reference the enclosing lexical environment, for instance). There’s no need to keep variables that are never referenced; that’s a pretty easy optimisation. This is getting away from the original point, though.

                        1. 1

                          i.e. with eval(),,

                          No.

                          Absolutely not.

                          eval() doesn’t have anything to do with closures.

                          Scheme didn’t have eval until R5RS, and even its eval can’t do what you’re suggesting.

                          PHP has closures, end-of.

                  2. 11

                    The only consistent property of PHP is how badly it’s designed, yet it somehow remains widely popular. There’s a social dynamic at play here that science has yet to unlock.

                    Yeah, PHP certainly has its issues. First theres the inconsistent syntax, like strpos vs base_convert. Then you have other issues like no method to return input with a newline, like Python print(), forcing explicit newline like echo "hello\n";.

                    But its widely popular because it works. Its significantly smaller than Python to install, and I would argue faster than Python in many cases. As a simple test, time how long it takes to do php -r 'echo "hello\n";' versus Python or frankly any other scripting language. I think the only faster language is Perl, and I usually stay away from Perl, as I view it as a “write only” language.

                    There’s no reason for that: I don’t write programs in PHP, never had to use it, and don’t expect to ever need it.

                    Author doesnt use PHP, and yet they felt compelled to write 900 word screed about it?

                    I recently came across a link to the PHP manual, and morbid curiosity that caused me to look through it.

                    Here is another point, the PHP manual. Again, PHP has its warts, but I would argue the PHP manual is the best programming language manual I have ever read. Every function gets its own page, not everything crammed into a giant page. This allows documentation to expand as the writers dont have to worry about an ever expanding megapage. Each page tells you the return value, what arguments are optional, whether values or references are expected, related functions. And important, comments. Look at this comment:

                    https://php.net/function.opendir#83990

                    It provides an algorithm for iterative traversing of a directory. An algorithm I use myself, as its pretty good. If author wants to slam PHP thats their business, and maybe justified in some narrow cases. But I think its unfair coming from someone who doesnt even use the language. In case anyone thinks Im biased, I maintain a comparison of programming languages:

                    https://cup.github.io/autumn

                    and above are just some of my thoughts after using 7 different languages over the last year.

                    1. 6

                      I usually stay away from Perl, as I view it as a “write only” language.

                      How ironic that you include this prejudice against another language while explaining the wrongness of prejudice against this one :)

                      1. 6

                        As a Perl enthusiast, there’s a lot of truth in that statement. Perl is so flexible and so fun that individual Perl hackers soon develop their own instance of TMTOWTDI, so the output of one Perl hacker can be hard to read for another.

                        I don’t have much confidence in my own cleverness so I try to minimize this, but the more you learn, the easier it is to use map and friends to “collapse” an assignment via an explicit loop to a oneliner. It’s no problem for me as this is an idiom I’ve leaned and grown comfortable with, but it does constitute an “internal slang” that others might not get, depending on their background and skill level.

                        Bondage-and-discipline languages like Python don’t have quite this issue.

                      2. 3

                        https://cup.github.io/autumn

                        This is really neat, thanks for sharing!

                        1. 2

                          Here’s another site that lists common tasks in multiple languages. When learning a new language, I often consult these resources.

                          http://www.rosettacode.org/

                        2. 2

                          I think the only faster language is Perl

                          I assume that means “I think the only faster interpreted language is Perl” or “I think the only interpreted language whose interpreter starts up faster than PHP’s is Perl” or something? Obviously an assembly version of hello world would be significantly faster than even just waiting for the Perl interpreter to get to the beginning of its main() function :P

                          Author doesn’t use PHP, and yet they felt compelled to write 900 word screed about it?

                          It can be interesting to analyze how something works even if you don’t personally use that thing. Criticism can be valid even when it’s not coming from someone who uses the thing being criticized. I agree though that some parts of this article isn’t good criticism; the part about closures is good (assuming it is correct, which it looks like it might not be), but just throwing in unsubstantiated claims like “The reason PHP has sigils is that Perl had them and PHP copied Perl without knowing why Perl had them” is unnecessary.

                        3. 2

                          Why does the shell command language use sigils? Because it’s built atop interactive command line usage, where bare words are taken literally and variables are the exception. Why does Perl use sigils? Because it was originally designed as an alternative to shell scripts, so it mimicked that syntax. Why does PHP use sigils? Because Perl did.

                          This interested me the most. Other than scripting languages, I find only Ruby’s use of sigils to be actually useful. It uses the sigils to distinguish the scope ($ for global, @ for instance, and @@ for class). This was really helpful when I was programming in ruby, and a feature that I miss in other languages (The self in Python helps too.)

                          I have sometimes tried to distinguish the local variables from parameter names by a _ suffix, but it is only useful in large functions.

                          1. 3

                            Use of sigils makes much more sense in Shell, Perl, and PHP than the author gives it credit for. With sigils it’s easy to embed variables in text ("Hello, $celestial_object"). Shell, Perl, and PHP were all started as text processing or template languages, so this was (is?) a common enough occurrence that it makes sense.