FAQ
See this 3v4l (contents at bottom of the message): http://3v4l.org/pHkf7

I think Bar::bar() should definitely return 'Bar' (currently returns 'Foo')
but what about the Bar::Baz() call?

Until today I didn't even know you could declare a static anonymous
function, so I'm not really sure what the expected behavior is.

Script contents:
<?php

class Foo {
static function bar() {
         $foo = static function() {
             return get_called_class();
         };

         return $foo();
     }
static function baz() {
         $foo = function() {
             return get_called_class();
         };

         return $foo();
     }
}

class Bar extends Foo {

}


assert(Bar::bar() === 'Bar');
assert(Bar::baz() === 'Bar');

Search Discussions

  • Tjerk Meesters at May 8, 2014 at 10:22 pm
    Hi
    On 9 May, 2014, at 6:02 am, Levi Morrison wrote:

    See this 3v4l (contents at bottom of the message): http://3v4l.org/pHkf7

    I think Bar::bar() should definitely return 'Bar' (currently returns 'Foo')
    but what about the Bar::Baz() call?

    Until today I didn't even know you could declare a static anonymous
    function, so I'm not really sure what the expected behavior is.

    Script contents:
    <?php

    class Foo {
    static function bar() {
    $foo = static function() {
    return get_called_class();
    };
    From what I gather, the use of static on closures only limits as to what you can bind it to, i.e. ->bindTo() will not accept an instance to bind to.
    return $foo();
    }
    static function baz() {
    $foo = function() {
    return get_called_class();
    };

    return $foo();
    }
    }

    class Bar extends Foo {

    }


    assert(Bar::bar() === 'Bar');
    assert(Bar::baz() === 'Bar');
  • Sanford Whiteman at May 8, 2014 at 11:43 pm

    I think Bar::bar() should definitely return 'Bar' (currently returns
    'Foo') but what about the Bar::Baz() call?
    I kinda agree, but that ship has sailed and it would be a BC break.

    You can do $foo->bindTo(null,Bar) even if the closure is static.

    Actually, it seems that when you call the parent function statically,
    the child closure is considered static no matter what else you do. So
    even force-running a parent function statically at runtime
    (disregarding the warning) means it and its child closures will
    behave as if they had the `static` keyword.

    I note in your 3v4l that HHVM does not follow the same rules.

    -- S.
  • Stas Malyshev at May 9, 2014 at 8:36 pm
    Hi!
    Until today I didn't even know you could declare a static anonymous
    function, so I'm not really sure what the expected behavior is.
    Static anon function means no $this is captured if this function is
    declared within method and no $this will be available inside.


    --
    Stanislav Malyshev, Software Architect
    SugarCRM: http://www.sugarcrm.com/
    (408)454-6900 ext. 227
  • Levi Morrison at May 11, 2014 at 3:12 am
    There was a reply to this list from Sanford Whiteman which I never
    received: http://marc.info/?l=php-internals&m=139959267615452&w=2

    Contents posted below:
    I think Bar::bar() should definitely return 'Bar' (currently returns
    'Foo') but what about the Bar::Baz() call?
    I kinda agree, but that ship has sailed and it would be a BC break.

    You can do $foo->bindTo(null,Bar) even if the closure is static.

    Actually, it seems that when you call the parent function statically,
    the child closure is considered static no matter what else you do. So
    even force-running a parent function statically at runtime
    (disregarding the warning) means it and its child closures
    will behave as if they had the `static` keyword.

    I note in your 3v4l that HHVM does not follow the same rules.

    -- S.
  • Levi Morrison at May 11, 2014 at 3:18 am

    On Sat, May 10, 2014 at 9:12 PM, Levi Morrison wrote:
    I think Bar::bar() should definitely return 'Bar' (currently returns
    'Foo') but what about the Bar::Baz() call?
    I kinda agree, but that ship has sailed and it would be a BC break.
    Yes... but we fix bugs all the time that are technically BC breaks. Do you
    really think we shouldn't fix this?

    I note in your 3v4l that HHVM does not follow the same rules.
    >

    I think HHVM gets the Bar::bar() case correct and we should fix it.

    I'm not sure if I agree with HHVM's outcome on Bar::baz(). To me the
    closure is non-static which means it won't invoke late static binding. This
    is something I'd like to discuss; what do you guys think about that?
    Another option is to implicitly promote closures inside of static contexts
    to be also be static; this is basically what HHVM does.
  • Sanford Whiteman at May 11, 2014 at 4:38 am

    Yes... but we fix bugs all the time that are technically BC breaks. Do you
    really think we shouldn't fix this?
    My thought was: if there's a place for get_called_class() in a closure
    in production code, it's been tested to expect the current behavior.
    Every time I've used g_c_c() it was to set up some delicate runtime
    logic.

    But if g_c_c() always returns the compile-time class of the parent
    method, that's a value you already know from inspecting the code. So
    the call is likely unnecessary. It could come from cut-and-paste...
    things happen. But probably not doing anything that can't be done
    without it.

    So I'm coming around to agreeing on a necessary BC break.
    Another option is to implicitly promote closures inside of static contexts
    to be also be static; this is basically what HHVM does.
    PHP does this! That's why you get 'Cannot bind an instance to a static
    closure' if you closure->bindTo() inside a static method, even if the
    closure itself is not keyworded `static`.

    The difference between HHVM and PHP is the default class scope of the
    closure. PHP makes the decision that the owning class scope of the
    closure is the compile-time class of the parent method. Why this was
    done I couldn't say.

    -- S.
  • Levi Morrison at May 13, 2014 at 4:25 pm
    Another option is to implicitly promote closures inside of static
    contexts
    to be also be static; this is basically what HHVM does.
    PHP does this! That's why you get 'Cannot bind an instance to a static
    closure' if you closure->bindTo() inside a static method, even if
    the closure itself is not keyworded `static`.
    I didn't explain that well enough; I meant that it automatically promotes
    the
    closure to be 'static' in that it uses late static binding.
    The difference between HHVM and PHP is the default class scope of the
    closure. PHP makes the decision that the owning class scope of the
    closure is the compile-time class of the parent method. Why this was
    done I couldn't say.
    This is actually the same issue as the one above. Basically the closures
    aren't respecting late static binding and I am pretty sure it was just an
    oversight, not a conscious decision.
  • Sanford Whiteman at May 14, 2014 at 6:06 pm

    Basically the closures aren't respecting late static binding and I
    am pretty sure it was just an oversight, not a conscious decision.
    I feel you're right and a bug should be submitted.

    Closures (speaking across languages) are supposed to stay aware of
    their lexical scope, but that is what get_class() is for, not
    get_called_class().

    -- S.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupphp-internals @
categoriesphp
postedMay 8, '14 at 10:02p
activeMay 14, '14 at 6:06p
posts9
users5
websitephp.net

People

Translate

site design / logo © 2022 Grokbase