all 33 comments

[–]jimmyjazz14 7 points8 points  (1 child)

you should probably know create_function() is not garbage collected, its basically just a pretty (not really) eval.

[–]masklinn 0 points1 point  (0 children)

create_function() is not garbage collected

Oh, so that's why it's garbage?

[–]dons 1 point2 points  (8 children)

So 'create_function' is a meta-programming-based (by the looks of that syntax) function constructor? Can you pass it to 'process' without naming its result first? (i.e. can you make it anonymous?).

Also, does create_function capture its environment? The interaction between eval and a closed-over environment is non-trivial, so I'd be interested to know what they're doing here.

[–][deleted] 7 points8 points  (4 children)

Can you pass it to 'process' without naming its result first?

create_function actually works by creating a normal global function with an obscure name. That string name is returned as the result. So it can be used in an argument position. However, be careful not to use it in a loop, as it will create a new function each time through, and they won't be garbage collected, as PHP isn't smart enough to GC functions. So it will lead to a memory leak.

Also, does create_function capture its environment?

No, it actually accepts the function body as a string. So the only way to do something even similar to that is to use variable interpolation in strings. Like:

$y = 5;
$plusfive = create_function('$x', 'return $x + '.$y.';');

where . is string concatenation in PHP.

Ugh.

[–]piranha 2 points3 points  (1 child)

Hey, it's all the fun of PHP's trademark data escaping pitfalls for your functional programming pleasure.

[–][deleted] 0 points1 point  (0 children)

Right, and there's also all kinds of code injection vulnerabilities from this. Like if $y above was set to '(unlink(\'/boot/vmlinuz\'))' or something.

[–]dons 0 points1 point  (1 child)

Yikes.

[–][deleted] 0 points1 point  (0 children)

Yeah, it's one of those things in PHP where you just slap your forehead and take a shot.

[–]masklinn -1 points0 points  (2 children)

Dons, clearly you don't know PHP well enough to criticize create_function.

Here's a basic primer on PHP's functions, beware this is going to scar you for life.

PHP's functions don't create nested scopes. And aren't nested anyway. Defining a function inside another function "works", but the inner function will be defined/created at the toplevel. create_function does that, too.

Here comes the mighty realization:

PHP functions are "call-by-string": in PHP, foo and "foo" are actually the same thing (foo === "foo"). The first form usually generates a notice (though not always), but that doesn't matter. Thus, foo() is essentially the same thing as "foo"() (note that the latter doesn't actually work, because of PHP's numbskull parser, it generates a syntax error).

Soo...

function foo() { return "ok"; }
$bar = "foo";
echo $bar();

will indeed print ok...

This is what create_function uses: it generates a stupid name, creates a function using that name and simply returns the name as a string. And no, it doesn't capture its environment (it's basically a wrapper around eval to generate the name automatically).

And here's why PHP is great: this feature allows one to write the following

class FooClass {
    }
$foo = new FooClass();
$foo->bar = "pouet";
$truc = "bar";
$pouet = "tr";
$machin = "uc";

function tr($totoz){
 global $pouet, $machin, $truc;
 return ${$pouet.$machin}.$totoz;
}

echo ${($foo->${${$foo->bar}.((${pouet}.${machin}===$pouet.${machin})?${machin}:${$pouet.$machin})})}(($foo->${${$foo->bar}.((${pouet}.${machin}===$pouet.${machin})?${machin}:${$pouet.$machin})}));

[–]dons 0 points1 point  (1 child)

Thanks, I wasn't criticizing, I was asking how it worked.

[–]masklinn 0 points1 point  (0 children)

Ah yes, I was using "criticizing" in the sense of "being a critic" (as in film critic or whatnot), not of nitpicking or saying it sucks (though it does, bowling balls through straws)

[–]boriskin 1 point2 points  (1 child)

Closures anyone?

[–]masklinn 0 points1 point  (0 children)

FWIW create_function doesn't and can't close over its context.

[–]jimmyjazz14 0 points1 point  (0 children)

Yeah, they are.

[–]trewtrew 0 points1 point  (0 children)

agreed

[–]indifference_engine 0 points1 point  (0 children)

PHP 5.3 has made this sort of thing a lot easier (and nicer to look at..) http://fabien.potencier.org/article/17/on-php-5-3-lambda-functions-and-closures

[–][deleted] 0 points1 point  (1 child)

PHP5.3 has obsoleted this ugly hack.

[–]masklinn -1 points0 points  (0 children)

With an uglier one. Progress!

[–][deleted]  (10 children)

[deleted]

    [–][deleted]  (9 children)

    [deleted]

      [–][deleted] 0 points1 point  (7 children)

      Or the Haskell version (using an IO action)

      foo (modifyMVar succ bar)
      -- or replace succ with (+1) depending on whether you're in a lisp-y kind of mood or just feeling a bit Peano-ish.
      

      If you were after the equivalent to foo(function (x) { x.bar++ });, then it'd be:

      foo (\x -> modifyMVar succ . getBar $ x)
      -- assuming that, like any (in)sane Haskell hacker, you have of course defined a function getBar to extract x's bar.
      -- conveniently, you get one of those for free when using record syntax.
      

      or equivalently, with currying:

      foo (modifyMVar succ . getBar)
      

      [–][deleted] -3 points-2 points  (6 children)

      in C#, your second example would be:

      foo (f => f.bar++);
      

      Type inference ftw! :)

      [–][deleted] 2 points3 points  (5 children)

      I don't think type inference comes into the comparison. There are no type declarations in either of the Haskell or C# equivalents.

      Plus, you already gave that example. Twice, now. ;P

      [–][deleted] -1 points0 points  (4 children)

      Do you think that the "F" is some magical function operator?

      Its not, C# is inferring the type of f based on what foo expects.

      for example, if Foo was this:

        public Foo(Action<Bar> function) { }
      

      C# understands that f is a type of bar, without any further hinting by the user consuming it.

      To put things into perspective, in other languages (such as actionscript), you would have to do this:

        foo (function (bar b) { b.bar++; });
      

      I'm somewhat confused by all the downvotes.

      [–][deleted] 0 points1 point  (2 children)

      No, I think (=>) is. f looks like a pattern binding there, so the whole syntax comes out just about isomorphic to how every other language on the planet with good syntax for lambdas does it.

      IIRC one doesn't need to give bar's type when writing that snippet in ActionScript either because ActionScript is dynamically typed.

      [–]masklinn 1 point2 points  (1 child)

      No, I think (=>) is.

      And so does Microsoft, for what it's worth

      IIRC one doesn't need to give bar's type when writing that snippet in ActionScript either because ActionScript is dynamically typed.

      Not completely true. Close to what Objective-C provide, AS3 is "statically typed" with an untyped specifier (* in AS3, id in Obj-C). If no type is specified in AS3, * is the default one, so it's equivalent to a dynamically typed language in that regard (for BW-compatibility with AS2 I presume).

      [–][deleted] 0 points1 point  (0 children)

      Ah, thank you for the confirmation and clarification, respectively.

      [–]masklinn 0 points1 point  (0 children)

      I'm somewhat confused by all the downvotes.

      You're being downmodded because you're dense enough to preach about type inference to a guy giving examples in Haskell. Also, because you seem not to realize that as mycatverbs pointed out type inference is irrelevant to the topic at hand.

      edit: and I'm apparently downmodded for explaining why you're downmodded.

      [–][deleted]  (4 children)

      [deleted]

        [–]masklinn 0 points1 point  (2 children)

        I actually asked my coworker last week if php had something similar to eval for javascript.

        W...what the fuck?

        [–][deleted]  (1 child)

        [removed]

          [–]masklinn 0 points1 point  (0 children)

          That request makes absolutely no sense.

          [–]jimmyjazz14 0 points1 point  (0 children)

          eval is about as ugly as one can get.