[patch] Dynamic access of static members/methods, and constants

php.internals

Etienne Kneuss

19 years ago
Hi, I've already proposed that 1-2 months ago, but now seems to be a good time to discuss new things, so let's try again: I believe it would be nice to be able to dynamically reference static members, constants, and methods. Currently, there is no way to do that and the only way would be to create a static method and use call_user_func(array($classname, 'getThat')); In other words: class A { public static $foo = 'value1'; const gee = 'value2'; public static function bar() { return 'value3'; } // old way: public static function getFoo() { return self::$foo; } public static function getGee() { return self::gee; } } $classname = 'A'; echo $classname::$foo; // value1 echo $classname::gee; // value2 echo $classname::bar(); // value3 // --- instead of: --- $classname = 'A'; echo call_user_func(array($classname, 'getFoo')); // value1 echo call_user_func(array($classname, 'getGee')); // value2 echo call_user_func(array($classname, 'bar')); // value3 which is quite slow. Please take a look at the patch[1] I made for it. Comments would be appreciated! Regards, 1: http://patches.colder.ch/Zend/dynamic-static-calls.patch?markup
-- Etienne Kneuss http://www.colder.ch colder@php.net Men never do evil so completely and cheerfully as when they do it from a religious conviction. -- Pascal

Edin Kadribasic

19 years ago
+1 Nice to be able to do this directly without resorting to call_user_func(). Edom Etienne Kneuss wrote:

Antony Dovgal

19 years ago
On 04/27/2007 04:37 PM, Etienne Kneuss wrote:
> Hi, > > I've already proposed that 1-2 months ago, but now seems to be a good > time to discuss new things, so let's try again: > > I believe it would be nice to be able to dynamically reference static > members, constants, and methods. > > Currently, there is no way to do that and the only way would be to > create a static method and use call_user_func(array($classname, 'getThat')); > > In other words:
I'm +0 if it's for HEAD only. Also I can see only two tests at the moment, we'll need MUCH more. There are so much combinations to test: unicode & binary strings, numbers, arrays, objects, booleans etc. etc.
-- Wbr, Antony Dovgal

Tijnema !

19 years ago
On 4/27/07, Antony Dovgal <antony@zend.com> wrote:
> On 04/27/2007 04:37 PM, Etienne Kneuss wrote: > > Hi, > > > > I've already proposed that 1-2 months ago, but now seems to be a good > > time to discuss new things, so let's try again: > > > > I believe it would be nice to be able to dynamically reference static > > members, constants, and methods. > > > > Currently, there is no way to do that and the only way would be to > > create a static method and use call_user_func(array($classname, 'getThat')); > > > > In other words: > > I'm +0 if it's for HEAD only. > > Also I can see only two tests at the moment, we'll need MUCH more. > There are so much combinations to test: unicode & binary strings, numbers, arrays, objects, booleans etc. etc. > > -- > Wbr, > Antony Dovgal >
There are actually 3 tests.... Tijnema

David Coallier

19 years ago
+1 On 4/27/07, Tijnema ! <tijnema@gmail.com> wrote:
> On 4/27/07, Antony Dovgal <antony@zend.com> wrote: > > On 04/27/2007 04:37 PM, Etienne Kneuss wrote: > > > Hi, > > > > > > I've already proposed that 1-2 months ago, but now seems to be a good > > > time to discuss new things, so let's try again: > > > > > > I believe it would be nice to be able to dynamically reference static > > > members, constants, and methods. > > > > > > Currently, there is no way to do that and the only way would be to > > > create a static method and use call_user_func(array($classname, 'getThat')); > > > > > > In other words: > > > > I'm +0 if it's for HEAD only. > > > > Also I can see only two tests at the moment, we'll need MUCH more. > > There are so much combinations to test: unicode & binary strings, numbers, arrays, objects, booleans etc. etc. > > > > -- > > Wbr, > > Antony Dovgal > > > There are actually 3 tests.... > > Tijnema > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
-- David Coallier, Founder & Software Architect, Agora Production (http://agoraproduction.com) 51.42.06.70.18

Jingcheng Zhang

19 years ago
Hi, In this way, classes can be considered as polymorphism, just like objects. So is it OK to allow abstract static function in abstract class to support this feature directory? Currently it is forbidden in HEAD, only interfaces can have static function. Thanks 2007/4/27, Etienne Kneuss <colder@php.net>:
> > Hi, > > I've already proposed that 1-2 months ago, but now seems to be a good > time to discuss new things, so let's try again: > > I believe it would be nice to be able to dynamically reference static > members, constants, and methods. > > Currently, there is no way to do that and the only way would be to > create a static method and use call_user_func(array($classname, > 'getThat')); > > In other words: > > class A { > public static $foo = 'value1'; > const gee = 'value2'; > public static function bar() { return 'value3'; } > > // old way: > public static function getFoo() { return self::$foo; } > public static function getGee() { return self::gee; } > > } > > $classname = 'A'; > echo $classname::$foo; // value1 > echo $classname::gee; // value2 > echo $classname::bar(); // value3 > > // --- instead of: --- > > $classname = 'A'; > echo call_user_func(array($classname, 'getFoo')); // value1 > echo call_user_func(array($classname, 'getGee')); // value2 > echo call_user_func(array($classname, 'bar')); // value3 > > which is quite slow. > > Please take a look at the patch[1] I made for it. Comments would be > appreciated! > > Regards, > > > 1: http://patches.colder.ch/Zend/dynamic-static-calls.patch?markup > > -- > Etienne Kneuss > http://www.colder.ch > colder@php.net > > Men never do evil so completely and cheerfully as > when they do it from a religious conviction. > -- Pascal > > Index: Zend/zend_language_parser.y > =================================================================== > RCS file: /repository/ZendEngine2/zend_language_parser.y,v > retrieving revision 1.179 > diff -u -r1.179 zend_language_parser.y > --- Zend/zend_language_parser.y 4 Mar 2007 16:25:57 -0000 1.179 > +++ Zend/zend_language_parser.y 6 Mar 2007 14:43:49 -0000 > @@ -642,6 +642,12 @@ > | fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM > variable_without_objects '(' { zend_do_end_variable_parse(BP_VAR_R, 0 > TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } > function_call_parameter_list > ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, > 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} > + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { > zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } > + function_call_parameter_list > + ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, > 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} > + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM > variable_without_objects '(' { zend_do_end_variable_parse(BP_VAR_R, 0 > TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } > + function_call_parameter_list > + ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, > 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} > | variable_without_objects '(' { > zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); > zend_do_begin_dynamic_function_call(&$1 TSRMLS_CC); } > function_call_parameter_list ')' > { zend_do_end_function_call(&$1, &$$, &$4, 0, 1 > TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} > @@ -795,6 +801,11 @@ > > static_member: > fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM > variable_without_objects { $$ = $3; zend_do_fetch_static_member(&$$, &$1 > TSRMLS_CC); } > + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM > variable_without_objects { $$ = $3; zend_do_fetch_static_member(&$$, &$1 > TSRMLS_CC); } > +; > + > +variable_class_name: > + reference_variable { zend_do_end_variable_parse(BP_VAR_R, 0 > TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } > ; > > > @@ -930,6 +941,7 @@ > > class_constant: > fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING > { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT TSRMLS_CC); } > + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { > zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT TSRMLS_CC); } > ; > > %% > Index: tests/lang/041.phpt > =================================================================== > RCS file: tests/lang/041.phpt > diff -N tests/lang/041.phpt > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ tests/lang/041.phpt 6 Mar 2007 14:43:49 -0000 > @@ -0,0 +1,14 @@ > +--TEST-- > +Dynamic access of static members > +--FILE-- > +<?php > +class A { > + public static $b = 'foo'; > +} > +$classname = 'A'; > +echo $classname::$b; > +?> > +===DONE=== > +--EXPECT-- > +foo > +===DONE=== > Index: tests/lang/042.phpt > =================================================================== > RCS file: tests/lang/042.phpt > diff -N tests/lang/042.phpt > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ tests/lang/042.phpt 6 Mar 2007 14:43:49 -0000 > @@ -0,0 +1,14 @@ > +--TEST-- > +Dynamic access of constants > +--FILE-- > +<?php > +class A { > + const B = 'foo'; > +} > +$classname = 'A'; > +echo $classname::B; > +?> > +===DONE=== > +--EXPECT-- > +foo > +===DONE=== > Index: tests/lang/043.phpt > =================================================================== > RCS file: tests/lang/043.phpt > diff -N tests/lang/043.phpt > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ tests/lang/043.phpt 6 Mar 2007 14:43:49 -0000 > @@ -0,0 +1,14 @@ > +--TEST-- > +Dynamic call for static methods > +--FILE-- > +<?php > +class A { > + static function foo() { return 'bar'; } > +} > +$classname = 'A'; > +echo $classname::foo(); > +?> > +===DONE=== > +--EXPECT-- > +bar > +===DONE=== > > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php >
-- Best regards, Jingcheng Zhang Room 304, Dormitory 26 of Yuquan Campus, Zhejiang University P.R.China

Stanislav Malyshev

19 years ago
> I've already proposed that 1-2 months ago, but now seems to be a good > time to discuss new things, so let's try again: > > I believe it would be nice to be able to dynamically reference static > members, constants, and methods. > > Currently, there is no way to do that and the only way would be to > create a static method and use call_user_func(array($classname, > 'getThat'));
Could you describe a couple of use cases where you would use such things (i.e. in real world scripts/libraries)?
-- Stanislav Malyshev, Zend Products Engineer stas@zend.com http://www.zend.com/

Etienne Kneuss

19 years ago
Hi, Stanislav Malyshev wrote:
> > Could you describe a couple of use cases where you would use such > things (i.e. in real world scripts/libraries)?
Sure, let's take an example: You have a library that uses a factory pattern, but you'd like to cache those already generated objects in a static variable in the class. Now, this feature is required in many classes and you'd not like to duplicate too much code, so a solution would be: class MySuperClass { private static $_objectsLoaded = array(); public static function factory($pkId, $classname = __CLASS__) { if(isset($_objectsLoaded[$classname][$pkId])) { return $_objectsLoaded[$classname][$pkId]; } $o = new $classname(); //load stuff from the database $table = $classname::$_table; $pkField = $classname::$_pkField; // build query using $table, and $pkField, load stuff into $o, etc.. if(!is_array(self::$_objectsLoaded[$classname])) { self::$_objectsLoaded[$classname] = array(); } self::$_objectsLoaded[$classname][$pkId] = $o; return $o; } public static function create($classname = __CLASS__) { $o = new $classname(); // ... return $o; } } class MyClass extends MySuperClass { protected static $_pkField = 'id'; protected static $_table = 'theTable'; public static factory($pkId, $classname = __CLASS__) { return parent::factory($pkId,$classname); } public static create($classname = __CLASS__) { return parent::create($classname); } // ... } There may be some typos in the code above that makes its syntax incorrect, but the idea is here. Now, as you can see, because late static binding is not yet implemented and probably never will be because of the overhead it might introduce, you've to pass the classname as a parameter and use it to request things from the child's class, at this point, being able to do that using that $classname:: shortcut is quite elegant, instead of having to use overkill call_user_func calls as all those _get*() methods would have to be redefined in every the child classes. I wouldn't mind having to use multiple call_user_func calls for that purpose if I knew it was too hard to implement that $classname:: thing, but it's so easy that I really believe it's a feature worth having. And PHP is also about multiple ways of doing something, right ? :)
-- Etienne Kneuss http://www.colder.ch colder@php.net Men never do evil so completely and cheerfully as when they do it from a religious conviction. -- Pascal