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

- Thread: https://externals.io/message/29067
- Original archive: https://news-web.php.net/php.internals/29067
- Started by Etienne Kneuss on 2007-04-27T12:37:07+00:00
- Messages: 8
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #29067 — Etienne Kneuss — 2007-04-27T12:37:07+00:00

URL: https://externals.io/message/29067#29067

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

---

## #29068 — Edin Kadribasic — 2007-04-27T12:54:09+00:00

URL: https://externals.io/message/29067#29068 · In reply to: #29067

+1

Nice to be able to do this directly without resorting to `call_user_func()`.

Edom


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:
> 
> 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

---

## #29069 — Antony Dovgal — 2007-04-27T12:54:15+00:00

URL: https://externals.io/message/29067#29069 · In reply to: #29067

> 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

---

## #29072 — Tijnema ! — 2007-04-27T13:30:52+00:00

URL: https://externals.io/message/29067#29072 · In reply to: #29069

> 
> > […]
>
> 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

---

## #29078 — David Coallier — 2007-04-27T16:35:56+00:00

URL: https://externals.io/message/29067#29078 · In reply to: #29072

+1


> 
> > […]
> There are actually 3 tests....
>
> Tijnema
>
> --
> 
> 
>
>


-- 
David Coallier,
Founder & Software Architect,
Agora Production (http://agoraproduction.com)
51.42.06.70.18

---

## #29156 — Jingcheng Zhang — 2007-05-03T14:50:10+00:00

URL: https://externals.io/message/29067#29156 · In reply to: #29067

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===
>
>
> --
> 
> 
>



-- 
Best regards,
Jingcheng Zhang
Room 304, Dormitory 26 of Yuquan Campus, Zhejiang University
P.R.China

---

## #29158 — Stanislav Malyshev — 2007-05-03T14:59:34+00:00

URL: https://externals.io/message/29067#29158 · In reply to: #29067

> 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/

---

## #29161 — Etienne Kneuss — 2007-05-03T17:01:17+00:00

URL: https://externals.io/message/29067#29161 · In reply to: #29158

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
