Edit report at http://bugs.php.net/bug.php?id=53009&edit=1

 ID:                 53009
 Comment by:         acid24 at gmail dot com
 Reported by:        acid24 at gmail dot com
 Summary:            Weird behavior of method_exists with anonymous
                     functions
 Status:             Wont fix
 Type:               Bug
 Package:            Class/Object related
 Operating System:   Ubuntu 10.04
 PHP Version:        5.3.3
 Block user comment: N

 New Comment:

Thank you for the clear explanation. 



For anyone interested I found that Reflection gives me the "correct"
behavior.



<?php

$lambda = function() {};



$r = new ReflectionObject( $lambda );

var_dump( $r->hasMethod( '__invoke' ) );

$r = new ReflectionClass( get_class( $lambda ) );

var_dump( $r->hasMethod( '__invoke' ) );

?>



outputs



bool(false)

bool(false)


Previous Comments:
------------------------------------------------------------------------
[2010-10-07 14:46:10] cataphr...@php.net

In PHP, not all methods are created equal.



Normal classes have a structure wherein the declared methods are stored
-- the class entry function table. method_exists returns true if a
method exists in such table.



But there's another way to obtain methods -- through the get_method
handler. See http://wiki.php.net/internals/engine/objects#get_method

method_exists(), if given an instance, calls this handler.



The handler table is associated to instances only; from the class entry,
you cannot know which handler table would be used in instances of that
class. 



Therefore, it's possible to have method_exists() return true if given an
instance and false if given the class of that instance as a string.



In this case, there's a twist. method_exists() also returns false if the
 function given by the get_method handler has the flag
ZEND_ACC_CALL_VIA_HANDLER, which means the method was generated
on-the-fly. This is the case with Closure's __invoke, but the
implementation of method_exists has a special exception for the Closure
class, and returns true there.



This could be "fixed" by removing the exception and returning false all
the time, but this wouldn't fix the bigger issue -- that you can have
method_exists returns true with an object and false with the class of
the object. So I'd mark this Wont Fix, but let's see if someone thinks
otherwise.

------------------------------------------------------------------------
[2010-10-07 10:44:17] acid24 at gmail dot com

provided wrong email address

------------------------------------------------------------------------
[2010-10-07 10:27:32] acid24 at gmail dot com

Description:
------------
method_exists() has a weird behavior when used on anonymous functions.
One would expect that testing the variable that holds the anonymous
function and the class of the anonymous function (Closure) to either
have or not the __invoke method. Instead method_exists() reports that
the variable that holds the anonymous function HAS an __invoke method
and the class of the anonymous function HAS NOT an __invoke method. Is
this behavior correct? If yes, maybe somebody can explain why. Thank you
in advance.

Test script:
---------------
<?php



$lambda = function() {};



var_dump( method_exists( $lambda, '__invoke' ) );

var_dump( method_exists( get_class( $lambda ), '__invoke' ) );

Expected result:
----------------
boolean(false)

boolean(false)



or 



boolean(true)

boolean(true)

Actual result:
--------------
boolean(true)

boolean(false)


------------------------------------------------------------------------



-- 
Edit this bug report at http://bugs.php.net/bug.php?id=53009&edit=1

Reply via email to