# late static binding php6

- Thread: https://externals.io/message/33290
- Original archive: https://news-web.php.net/php.internals/33290
- Started by Mike Lively on 2007-11-18T23:10:12+00:00
- Messages: 31
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/33290.md?page=2
- 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

---

## #33290 — Mike Lively — 2007-11-18T23:10:12+00:00

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

Stanislav Malyshev wrote:

> > […]
>
> Actually, I don't think it was. If you want objects, why not use the
> real thing? LSB was created to solve just one particular problem -
> inability to distinguish A::method() from B::method() if B extends A.

Being one of the original people requesting this I would have to say
that you aren't completely accurate in that statement. That may have
been the goals of the most recent patch's collaborators but it certainly
wasn't mine. The reason I originally wanted it was because the way
statics were originally implemented was too rigid to do things that I
wanted to with them. LSB was a way to provide a flexible inheritance
model for static classes. This would allow for the framework creator's
dream of not having to instantiate objects for the sole purpose of
instantiating new objects:

$model = new Author();
$more_models = $model->findByName('Mike');

Instead you could place your 'factory' code into a base class as a
static and extend it appropriately. This goal was met, but with yet
another severe limitation in that you lose the ability to reimplement
after you extend. In my opinion this is foundational to object oriented
design and I know that alot of people agree with me. So in that vain
what's wrong with going the full length on a new feature that isn't set
in stone?

>
> > […]
> "more complex" is not always better.

Rest assured that this is not the bad kind of 'more complex' I believe
that with a large number of OO programmers this is going to be more
natural. Bear in mind that this patch is in a large part geared to
please those people that though self:: should have referred to the
calling class to begin with. I can all but guarantee that you will be
hearing the same arguments about 'parent::' within a fairly short amount
of time after 5.3 goes out. Maybe then we will talk about 'Later Static
Binding' :P.

---

## #33315 — Mike Lively — 2007-11-19T06:44:03+00:00

URL: https://externals.io/message/33290#33315 · In reply to: #33302

Jochem Maas wrote:
> Stanislav Malyshev wrote:
>   
> > […]
>
> class A {
> 	static function find($id) {
> 		// lets try and find a 'something'
> 	}
> }
>
> class B extends A {}
>
> // I'd like a 'B' please bob.
> $b = B::find( 1 );
>
>
>
> are you saying that A::find() can tell that it was called as B::find() ?
>   
No, your example would work. WHere it breaks down is if you want to
specialize B::find();

class B extends A {
    static function find($id) {
       /* do something special */
       parent::find($id);
    }
}


in that situation A::find(); would not be able to know it was being
called by B::find() because parent:: is considered an explicit class
name reference.

---

## #33297 — Stanislav Malyshev — 2007-11-19T09:18:24+00:00

URL: https://externals.io/message/33290#33297 · In reply to: #33290

> Rest assured that this is not the bad kind of 'more complex' I believe

I'm afraid I must disagree. The feature that was missing was to know the 
true calling class name. That was implemented. You can build from it, 
there's no need to add further complication to the language. You can 
easily find out the calling class for static call, you can easily find 
it's parent, provided one exists, you can easily call any method of this 
class.
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #33302 — Jochem Maas — 2007-11-19T12:07:01+00:00

URL: https://externals.io/message/33290#33302 · In reply to: #33297

Stanislav Malyshev wrote:
> > […]
> 
> I'm afraid I must disagree. The feature that was missing was to know the
> true calling class name. That was implemented. You can build from it,
> there's no need to add further complication to the language. You can
> easily find out the calling class for static call, you can easily find
> it's parent, provided one exists, you can easily call any method of this
> class.

class A {
	static function find($id) {
		// lets try and find a 'something'
	}
}

class B extends A {}

// I'd like a 'B' please bob.
$b = B::find( 1 );



are you saying that A::find() can tell that it was called as B::find() ?

---

## #33351 — Mike Lively — 2007-11-19T18:45:37+00:00

URL: https://externals.io/message/33290#33351

Stanislav Malyshev wrote:
> > […]
>
> By means of using `get_called_class()` and then using this information
> to call needed method of needed class.
There is still a disconnect somewhere.
<?php

class A
{
    static public function test()
    {
       echo `get_called_class()`;
    }
}

class B extends A
{
    static public function test()
    {
       parent::test();
    }
}


B::test();

?>

This will echo 'A'. So like I said you have no way here of telling that
B:: was used.

Now if you are talking about something like:

<?php

class A
{
    static public function test($called_class)
    {
       echo $called_class;
    }
}

class B
{
    static public function test()
    {
       parent::test(get_class());
    }
}

?>

Then there are two problems (sort of). First problem being, then why
bother with lsb, you can do this already (which more so a 'wth' as
opposed to a problem.) The second and much more prevelent problem is
that iirc you cannot do this kind of loose inheritance with statics in
php 6 without getting at least a strict error thrown (Please correct me
if I am wrong, I don't have the latest php6 code at the moment.)

?

---

## #33327 — Stanislav Malyshev — 2007-11-19T18:56:31+00:00

URL: https://externals.io/message/33290#33327 · In reply to: #33302

> class A {
> 	static function find($id) {
> 		// lets try and find a 'something'
> 	}
> }
> 
> class B extends A {}
> 
> // I'd like a 'B' please bob.
> $b = B::find( 1 );
> 
> 
> 
> are you saying that A::find() can tell that it was called as B::find() ?

Yes, this is exactly what LSB does.
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #33328 — Stanislav Malyshev — 2007-11-19T18:57:05+00:00

URL: https://externals.io/message/33290#33328 · In reply to: #33315

> in that situation A::find(); would not be able to know it was being
> called by B::find() because parent:: is considered an explicit class
> name reference.

It will be, just not by means of parent::.
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #33353 — Mike Lively — 2007-11-19T19:21:33+00:00

URL: https://externals.io/message/33290#33353 · In reply to: #33352

Stanislav Malyshev wrote:
> > […]
>
> What do you want parent::test() to mean?
>
> > […]
>
> Because it wasn't. parent::test() means A::test(). 'parent::' means
> 'parent class of the class where this statement is' in PHP. For B,
> it's A.
Yes but B::test() was called to start the call chain and in this
situation I want the B::test() method to decorate A::test() and it just
isn't possible without allowing parent:: to forward the called class or
introducing a new keyword.
>
> > […]
>
> If you can do it - do it.
I (and many other people) don't feel the need to do things this way and
it is slightly frustrating to see a patch implemented to allow us to
'sort of' do it cleanly but ultimately misses the mark. Especially when
it is probably a relatively minor change to support what we are asking
for. This is also a terrible argument to use against a new feature...but
that's an entirely separate matter.
>
> > […]
>
> What is 'loose inheritance'?

By loose inheritance I mean extending and overwriting a method while
changing that method's parameter list.

I apologize, I grabbed php6 and appear to have not remembered things
quite right. I thought that you could not change the parameter list of
inherited static methods which is not the case in php6. Although you
WILL have a problem if you program to interfaces. If static public
test() is declared in an interface that  A implements then you won't be
able to change the parameter list in B.

---

## #33352 — Stanislav Malyshev — 2007-11-20T02:49:51+00:00

URL: https://externals.io/message/33290#33352 · In reply to: #33351

>        parent::test();

What do you want parent::test() to mean?

> This will echo 'A'. So like I said you have no way here of telling that
> B:: was used.

Because it wasn't. parent::test() means A::test(). 'parent::' means 
'parent class of the class where this statement is' in PHP. For B, it's A.

> Then there are two problems (sort of). First problem being, then why
> bother with lsb, you can do this already (which more so a 'wth' as

If you can do it - do it.

> opposed to a problem.) The second and much more prevelent problem is
> that iirc you cannot do this kind of loose inheritance with statics in

What is 'loose inheritance'?
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #33366 — Gergely Hodicska — 2007-11-21T06:23:19+00:00

URL: https://externals.io/message/33290#33366 · In reply to: #33352

Hi!

> What do you want parent::test() to mean?
> Because it wasn't. parent::test() means A::test(). 'parent::' means 
> 'parent class of the class where this statement is' in PHP. For B, it's A.
When you use parent in your code you generally want to add some plus 
functionality to the parent class. But in this case if you use the 
parent the behavior of the parent class changes too.


Best Regards,
Felhő

---

## #33378 — Marco Kaiser — 2007-11-22T20:29:19+00:00

URL: https://externals.io/message/33290#33378 · In reply to: #33366

Hi List,

just to drop my note here, i asked (i think) 2 years ago for such a
feature to automate my singleton pattern. Not with late static
bindings this is possible.

<?php
class singleton
{
	static protected $_instance = null;

	static public function getInstance()
	{
	    $caller = `get_called_class()`;
	    if (!static::$_instance instanceof $caller) {
            static::$_instance = new $caller;
	    }

	    return static::$_instance;
	}
}

class foo extends singleton
{
}

var_dump(foo::getInstance());
var_dump(foo::getInstance());
?>

i think this will also drop much redundant code from some frameworks. :)
So this is one of my examples that helps much.


-- 
Marco Kaiser

---

## #33379 — Marco Kaiser — 2007-11-22T20:40:47+00:00

URL: https://externals.io/message/33290#33379 · In reply to: #33378

Hi again,

to explain the main idea a bit more, the code below work and moves the
main getInstance function from the class and its possible to abstract
this.
it would be cool to get the protected property also into the abstract
class. Any idea or maybe a solution in the near future?

<?php
abstract class singleton
{
	static public function getInstance()
	{
	    $caller = `get_called_class()`;
	    if (!static::$_instance instanceof $caller) {
            static::$_instance = new $caller;
	    }

	    return static::$_instance;
	}
}

class foo extends singleton {
	static protected $_instance = null;
}

class bar extends singleton {
	static protected $_instance = null;
}

var_dump(foo::getInstance());
var_dump(bar::getInstance());
var_dump(foo::getInstance());
var_dump(bar::getInstance());
?>


> Hi List,
>
> just to drop my note here, i asked (i think) 2 years ago for such a
> feature to automate my singleton pattern. Not with late static
> bindings this is possible.
>
> <?php
> class singleton
> {
>         static protected $_instance = null;
>
>         static public function getInstance()
>         {
>             $caller = `get_called_class()`;
>             if (!static::$_instance instanceof $caller) {
>             static::$_instance = new $caller;
>             }
>
>             return static::$_instance;
>         }
> }
>
> class foo extends singleton
> {
> }
>
> var_dump(foo::getInstance());
> var_dump(foo::getInstance());
> ?>
>
> i think this will also drop much redundant code from some frameworks. :)
> So this is one of my examples that helps much.
>
>
> --
> Marco Kaiser
>



-- 
Marco Kaiser

---

## #33385 — Richard Quadling — 2007-11-23T09:18:05+00:00

URL: https://externals.io/message/33290#33385 · In reply to: #33379

> Hi again,
>
> to explain the main idea a bit more, the code below work and moves the
> main getInstance function from the class and its possible to abstract
> this.
> it would be cool to get the protected property also into the abstract
> class. Any idea or maybe a solution in the near future?
>
> <?php
> abstract class singleton
> {
>         static public function getInstance()
>         {
>             $caller = `get_called_class()`;
>             if (!static::$_instance instanceof $caller) {
>             static::$_instance = new $caller;
>             }
>
>             return static::$_instance;
>         }
> }
>
> class foo extends singleton {
>         static protected $_instance = null;
> }
>
> class bar extends singleton {
>         static protected $_instance = null;
> }
>
> var_dump(foo::getInstance());
> var_dump(bar::getInstance());
> var_dump(foo::getInstance());
> var_dump(bar::getInstance());
> ?>
>
> 
> > […]
>
>
>
> --
> Marco Kaiser

<?php
abstract class singleton
{
       static protected $_instance = null;
       static public function getInstance()
       {
           $caller = `get_called_class()`;
           if (!static::$_instance instanceof $caller) {
           static::$_instance = new $caller;
           }

           return static::$_instance;
       }
}

class foo extends singleton {
}

class bar extends singleton {
}

var_dump(foo::getInstance());
var_dump(bar::getInstance());
var_dump(foo::getInstance());
var_dump(bar::getInstance());
?>

returns ...

object(foo)#1 (0) {
}
object(bar)#2 (0) {
}
object(foo)#1 (0) {
}
object(bar)#2 (0) {
}

in PHP 5.3.0-dev (cli) (built: Nov 20 2007 08:19:12)

I think this is great! Well done everyone. Unless I've completely
missed the point.


-- 
-----
Richard Quadling
Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731
"Standing on the shoulders of some very clever giants!"

---

## #33386 — Richard Quadling — 2007-11-23T09:21:51+00:00

URL: https://externals.io/message/33290#33386 · In reply to: #33385

> 
> > […]
>
> <?php
> abstract class singleton
> {
>        static protected $_instance = null;
>        static public function getInstance()
>        {
>            $caller = `get_called_class()`;
>            if (!static::$_instance instanceof $caller) {
>            static::$_instance = new $caller;
>            }
>
>            return static::$_instance;
>        }
> }
>
> class foo extends singleton {
> }
>
> class bar extends singleton {
> }
>
> var_dump(foo::getInstance());
> var_dump(bar::getInstance());
> var_dump(foo::getInstance());
> var_dump(bar::getInstance());
> ?>
>
> returns ...
>
> object(foo)#1 (0) {
> }
> object(bar)#2 (0) {
> }
> object(foo)#1 (0) {
> }
> object(bar)#2 (0) {
> }
>
> in PHP 5.3.0-dev (cli) (built: Nov 20 2007 08:19:12)
>
> I think this is great! Well done everyone. Unless I've completely
> missed the point.

Also, you can make the getInstance() method final so it cannot be
overridden in sub-classes...

<?php
abstract class singleton
{
       static protected $_instance = null;
       static final public function getInstance()
       {
           $caller = `get_called_class()`;
           if (!static::$_instance instanceof $caller) {
           static::$_instance = new $caller;
           }

           return static::$_instance;
       }
}

class foo extends singleton {
	public function getInstance() { return 'foobar'; }
}

class bar extends singleton {
}

var_dump(foo::getInstance());
var_dump(bar::getInstance());
var_dump(foo::getInstance());
var_dump(bar::getInstance());
?>

returns ...

Fatal error: Cannot override final method singleton::getInstance() in
C:\sing.php on line 18

So, a very useful addition to the language.

-- 
-----
Richard Quadling
Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731
"Standing on the shoulders of some very clever giants!"

---

## #33387 — Marco Kaiser — 2007-11-23T09:53:11+00:00

URL: https://externals.io/message/33290#33387 · In reply to: #33386

Hi Richard,

the problem is this:

<?php
abstract class singleton
{
    static protected $_instance;
    
	static final public function getInstance()
	{
	    $caller = `get_called_class()`;
	    if (!static::$_instance instanceof $caller) {
	        echo "NEW INSTANCE\n";
            static::$_instance = new $caller;
	    }

	    return static::$_instance;
	}
}

class foo extends singleton {
	static protected $_instance;
}

class bar extends singleton {
	static protected $_instance;
}

var_dump(foo::getInstance());
var_dump(bar::getInstance());
var_dump(foo::getInstance());
var_dump(bar::getInstance());
?>

NEW INSTANCE
object(foo)#1 (0) {
}
NEW INSTANCE
object(bar)#2 (0) {
}
object(foo)#1 (0) {
}
object(bar)#2 (0) {
}

This means i just called once the constructor for the singleton abstract for every main class (foo, bar)
But if you remove the static member $_instance from the foo and bar class you get this result:

NEW INSTANCE
object(foo)#1 (0) {
}
NEW INSTANCE
object(bar)#2 (0) {
}
NEW INSTANCE
object(foo)#1 (0) {
}
NEW INSTANCE
object(bar)#2 (0) {
}

You see that the constructor is called every time if you use more than 1 singleton class during script execution.
The problem is that the property isnt really inherited by the foo and bar class.

My idea or a possible solution would be to allow the definition of correct inheritance of the $_instance property or
to show me a way to set a static property dynamicly in the caller class.
Maybe Andi or Markus can explain this a bit more why this isnt possible. :)

-- Marco

> -----Original Message-----
> From: Richard Quadling [mailto:rquadling@googlemail.com]
> Sent: Friday, November 23, 2007 10:22 AM
> To: Marco Kaiser
> Cc: PHP Developers Mailing List
> Subject: Re: [PHP-DEV] late static binding php6
> 
> 
> > […]
> the
> > […]
> abstract
> > […]
> abstract
> > […]
> wrote:
> > […]
> a
> > […]
> frameworks. :)
> > […]
> 
> Also, you can make the getInstance() method final so it cannot be
> overridden in sub-classes...
> 
> <?php
> abstract class singleton
> {
>        static protected $_instance = null;
>        static final public function getInstance()
>        {
>            $caller = `get_called_class()`;
>            if (!static::$_instance instanceof $caller) {
>            static::$_instance = new $caller;
>            }
> 
>            return static::$_instance;
>        }
> }
> 
> class foo extends singleton {
> 	public function getInstance() { return 'foobar'; }
> }
> 
> class bar extends singleton {
> }
> 
> var_dump(foo::getInstance());
> var_dump(bar::getInstance());
> var_dump(foo::getInstance());
> var_dump(bar::getInstance());
> ?>
> 
> returns ...
> 
> Fatal error: Cannot override final method singleton::getInstance() in
> C:\sing.php on line 18
> 
> So, a very useful addition to the language.
> 
> --
> -----
> Richard Quadling
> Zend Certified Engineer :
> http://zend.com/zce.php?c=ZEND002498&r=213474731
> "Standing on the shoulders of some very clever giants!"

---

## #33389 — Marcus Boerger — 2007-11-23T11:22:30+00:00

URL: https://externals.io/message/33290#33389 · In reply to: #33386

Hello Richard,

  that kind of stuff is the reason we added LSB. There is only one tiny
thing I am not to happy about. You do not at all have to declare static
$instance. Simply because you never use it. And for that reason you guys
have your code worng. Use the following snippet for verification:
var_dump($u=foo::getInstance());
var_dump($v=bar::getInstance());
var_dump($w=foo::getInstance());
var_dump($x=bar::getInstance());
var_dump(array($u,$v,$w,$x));

When you want to have a factory of singletons that can create one single
member of every derived class than you need to add an array to store those
inside the abstract base class. That also allows to make that member
private and thereby disallowing any derived class to interfere with the
static member and get rid of them to overthrow the singleton limitation...
You also have no need for the instanceof operation with the array. See here:

<?php
abstract class singleton
{
        static private $instances = array();
        static final public function getInstance()
        {
                $caller = `get_called_class()`;
                if (!isset(self::$instances[$caller])) {
                        self::$instances[$caller] = new $caller;
                }
                return self::$instances[$caller];
        }
}

class foo extends singleton {
}

class bar extends singleton {
}

var_dump($u=foo::getInstance());
var_dump($v=bar::getInstance());
var_dump($w=foo::getInstance());
var_dump($x=bar::getInstance());
var_dump(array($u,$v,$w,$x));
?>

Friday, November 23, 2007, 10:21:51 AM, you wrote:

> 
> > […]

> Also, you can make the getInstance() method final so it cannot be
> overridden in sub-classes...

> <?php
> abstract class singleton
> {
>        static protected $_instance = null;
>        static final public function getInstance()
>        {
>            $caller = `get_called_class()`;
>            if (!static::$_instance instanceof $caller) {
>            static::$_instance = new $caller;
>            }

>            return static::$_instance;
>        }
> }

> class foo extends singleton {
>         public function getInstance() { return 'foobar'; }
> }

> class bar extends singleton {
> }

> var_dump(foo::getInstance());
> var_dump(bar::getInstance());
> var_dump(foo::getInstance());
> var_dump(bar::getInstance());
?>>

> returns ...

> Fatal error: Cannot override final method singleton::getInstance() in
> C:\sing.php on line 18

> So, a very useful addition to the language.

> -- 
> -----
> Richard Quadling
> Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731
> "Standing on the shoulders of some very clever giants!"




Best regards,
 Marcus

---

## #33390 — Richard Quadling — 2007-11-23T12:26:37+00:00

URL: https://externals.io/message/33290#33390 · In reply to: #33389

> Hello Richard,
>
>   that kind of stuff is the reason we added LSB. There is only one tiny
> thing I am not to happy about. You do not at all have to declare static
> $instance. Simply because you never use it. And for that reason you guys
> have your code worng. Use the following snippet for verification:
> var_dump($u=foo::getInstance());
> var_dump($v=bar::getInstance());
> var_dump($w=foo::getInstance());
> var_dump($x=bar::getInstance());
> var_dump(array($u,$v,$w,$x));
>
> When you want to have a factory of singletons that can create one single
> member of every derived class than you need to add an array to store those
> inside the abstract base class. That also allows to make that member
> private and thereby disallowing any derived class to interfere with the
> static member and get rid of them to overthrow the singleton limitation...
> You also have no need for the instanceof operation with the array. See here:
>
> <?php
> abstract class singleton
> {
>         static private $instances = array();
>         static final public function getInstance()
>         {
>                 $caller = `get_called_class()`;
>                 if (!isset(self::$instances[$caller])) {
>                         self::$instances[$caller] = new $caller;
>                 }
>                 return self::$instances[$caller];
>         }
> }
>
> class foo extends singleton {
> }
>
> class bar extends singleton {
> }
>
> var_dump($u=foo::getInstance());
> var_dump($v=bar::getInstance());
> var_dump($w=foo::getInstance());
> var_dump($x=bar::getInstance());
> var_dump(array($u,$v,$w,$x));
> ?>

Changing bar to extend from foo gives the same results.

We have a singleton of the class bar because somewhere in the chain it
has the singleton class.

Excellent.



>
> Friday, November 23, 2007, 10:21:51 AM, you wrote:
>
> > […]
>
> > […]
>
> > […]
>
> > […]
>
> > […]
>
> > […]
>
> > […]
> ?>>
>
> > […]
>
> > […]
>
> > […]
>
> > […]
>
>
>
>
> Best regards,
>  Marcus
>
>


-- 
-----
Richard Quadling
Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731
"Standing on the shoulders of some very clever giants!"

---

## #33391 — Marcus Boerger — 2007-11-23T13:02:53+00:00

URL: https://externals.io/message/33290#33391 · In reply to: #33390

Hello Richard,

  what's your point? The output of this script with updated checks and
inheritence still gives expected results:
<?php
abstract class singleton
{
        static private $instances = array();
        static final public function getInstance()
        {
                $caller = `get_called_class()`;
                if (!self::$instances[$caller] instanceof $caller) {
                        self::$instances[$caller] = new $caller;
                }
                return self::$instances[$caller];
        }
}

class foo extends singleton {
}

class bar extends singleton {
}

class baz extends bar {
}

var_dump($u = foo::getInstance());
var_dump($v = bar::getInstance());
var_dump($w = baz::getInstance());

var_dump($x = foo::getInstance());
var_dump($y = bar::getInstance());
var_dump($z = baz::getInstance());

var_dump(array($u, $v, $w, $x, $y, $z));
?>

If you wanted to prevent further inheritance you'd simply mark the class as
final. Say 'final class bar' would prevent existance of 'baz'. I wonder if
we shouldn't make this somehow into a testcase so that we know the desired
behavior stays as development of LSB continues.

marcus

Friday, November 23, 2007, 1:26:37 PM, you wrote:

> 
> > […]

> Changing bar to extend from foo gives the same results.

> We have a singleton of the class bar because somewhere in the chain it
> has the singleton class.

> Excellent.



> > […]


> -- 
> -----
> Richard Quadling
> Zend Certified Engineer : http://zend.com/zce.php?c=ZEND002498&r=213474731
> "Standing on the shoulders of some very clever giants!"




Best regards,
 Marcus

---

## #33392 — Marco Kaiser — 2007-11-23T13:22:32+00:00

URL: https://externals.io/message/33290#33392 · In reply to: #33389

Hi Marcus,

ahh now i know whats my thinking problem. :) the new introduced function
 `get_called_class()` function gives me the
information how to work around my problem. :) static isnt really required.
:)


-- Marco

> -----Original Message-----
> From: Marcus Boerger [mailto:helly@php.net]
> Sent: Friday, November 23, 2007 12:23 PM
> To: Richard Quadling
> Cc: Marco Kaiser; PHP Developers Mailing List
> Subject: Re: [PHP-DEV] late static binding php6
> 
> Hello Richard,
> 
>   that kind of stuff is the reason we added LSB. There is only one tiny
> thing I am not to happy about. You do not at all have to declare static
> $instance. Simply because you never use it. And for that reason you
> guys
> have your code worng. Use the following snippet for verification:
> var_dump($u=foo::getInstance());
> var_dump($v=bar::getInstance());
> var_dump($w=foo::getInstance());
> var_dump($x=bar::getInstance());
> var_dump(array($u,$v,$w,$x));
> 
> When you want to have a factory of singletons that can create one
> single
> member of every derived class than you need to add an array to store
> those
> inside the abstract base class. That also allows to make that member
> private and thereby disallowing any derived class to interfere with the
> static member and get rid of them to overthrow the singleton
> limitation...
> You also have no need for the instanceof operation with the array. See
> here:
> 
> <?php
> abstract class singleton
> {
>         static private $instances = array();
>         static final public function getInstance()
>         {
>                 $caller = `get_called_class()`;
>                 if (!isset(self::$instances[$caller])) {
>                         self::$instances[$caller] = new $caller;
>                 }
>                 return self::$instances[$caller];
>         }
> }
> 
> class foo extends singleton {
> }
> 
> class bar extends singleton {
> }
> 
> var_dump($u=foo::getInstance());
> var_dump($v=bar::getInstance());
> var_dump($w=foo::getInstance());
> var_dump($x=bar::getInstance());
> var_dump(array($u,$v,$w,$x));
> ?>
> 
> Friday, November 23, 2007, 10:21:51 AM, you wrote:
> 
> > […]
> the
> > […]
> abstract
> > […]
> abstract
> > […]
> wrote:
> > […]
> such a
> > […]
> frameworks.
> > […]
> 
> > […]
> 
> > […]
> 
> > […]
> 
> > […]
> 
> > […]
> 
> > […]
> ?>>
> 
> > […]
> 
> > […]
> 
> > […]
> 
> > […]
> http://zend.com/zce.php?c=ZEND002498&r=213474731
> > […]
> 
> 
> 
> 
> Best regards,
>  Marcus

---

## #33432 — Mike Lively — 2007-11-25T22:11:52+00:00

URL: https://externals.io/message/33290#33432 · In reply to: #33366

I have come up with three different patches that allow us to work around
the issue of parent:: being considered an 'explicit class reference' and
thus disallowing static:: to effectively used.

The patches are against 5.3. I also have patches against HEAD but I was
having problems getting run-tests.php to run against that code base (it
would hang on the first test no matter which set of tests I ws running.)

All three patches have different levels of intrusiveness to the engine
and all three patches have been tested against (and pass) the existing
lsb tests in Zend/tests/lsb_*.phpt

1.) lsb.parent-forwarding.patch
This patch modifies the behavior of only parent:: to not change
EG(called_class) to the parent of the current scope. With this change.

<?php

class A {
    public static function test() {
       echo `get_called_class()`."\n";
    }
}

class B extends A {
    public static function test() {
       parent::test();
    }
}

A::test();
B::test();

?>
will output:
A
B

It should be noticed that with this patch parent:: will always resolve
to the parent of the current scope, it will just not make any changes to
the called_scope (effectively)

2.) lsb.new-keyword.patch
This patch effectively does the same thing as the parent forwarding
patch, but does it by introducing a new keyword. I had no idea what to
call this keyword so for the time being I am using '__parentf'. If this
is a direction people want to go this can of course be changed with a
relatively simple search & replace in the patch file.

The code above would need to be changed to:

<?php

class A {
    public static function test() {
       echo `get_called_class()`."\n";
    }
}

class B extends A {
    public static function test() {
       __parentf::test();
    }
}

A::test();
B::test();

?>

This patch carries the same costs as the parent forwarding patch with
the additional costs of having to check for a new keyword when declaring
classes/namespaces/interfaces and calling static methods. Perhaps
someone knows a cheaper way to do this?

3.) lsb.forward_static_call.patch
This patch implements my desired functionality by using two new
functions: `forward_static_call()` and `forward_static_call_array()`. These
functions ares similar to the  call_user_func*() functions however the
first parameter is not a callback but a string specifying the desired
static method that exists in the current scope's parent class. The
function will error out with messages similar to parent:: if called from
outside of a class or from within a class that does not have a parent.

So with this patch the code would change to:

<?php

class A {
    public static function test() {
       echo `get_called_class()`."\n";
    }
}

class B extends A {
    public static function test() {
       forward_static_call(__FUNCTION__);
    }
}

A::test();
B::test();

?>

This patch is completely outside of the Zend engine and as such existing
lsb functionality is not affected at all.

So, with these three options on the table I think it is very clear that
what we are asking for can be done with varying levels of
'intrusiveness', so what does everyone think?

If one of these options looks worth pursuing I can put together the
tests I have written for all of them, cleanup the code, help with
documentation, etc.

- Mike Lively
http://www.digitalsandwich.com

---

## #33428 — Jeff Moore — 2007-11-25T22:45:19+00:00

URL: https://externals.io/message/33290#33428 · In reply to: #33392

Hi,

May I suggest renaming `get_called_class()` to get_static_class() to  
correspond with the use of the static:: keyword for late binding.

parent:: and `get_parent_class()` [no parameters] should also correspond  
when used in a static method context.

My preference is that parent:: be late binding.  I would also like to  
see an early bound __parent__ constant along the lines of __class__.

Best Regards,

Jeff

---

## #33430 — Etienne Kneuss — 2007-11-25T23:25:53+00:00

URL: https://externals.io/message/33290#33430 · In reply to: #33428

Hi,



>
> Hi,
>
> May I suggest renaming `get_called_class()` to get_static_class() to
> correspond with the use of the static:: keyword for late binding.


It was already kind of discussed, and get_called_class makes more sense IMO.
"static class" is not self-descriptive. The class returned is the class that
was initially
referenced for the call, as in the class "called" initially.


> parent:: and `get_parent_class()` [no parameters] should also correspond
> when used in a static method context.


They do, parent::foo(); should be the same as $class = `get_parent_class()`;
$class::foo();

Of course, we can't make parent:: reference the parent class of the called
one, as it would break BC.

As in:
class A { }
class B extends A { public static function test() { echo get_class(new
parent), '-', `get_parent_class()`; } }
class C extends B { }
C::test(); // A-A and not B-B


>
>
> My preference is that parent:: be late binding.  I would also like to
> see an early bound __parent__ constant along the lines of __class__.
>
> Best Regards,
>
> Jeff
>
> --
> 
> 
>
>
>


-- 
Etienne Kneuss
http://www.colder.ch

Men never do evil so completely and cheerfully as
when they do it from a religious conviction.
-- Pascal

---

## #33434 — Alexey Zakhlestin — 2007-11-26T09:24:03+00:00

URL: https://externals.io/message/33290#33434 · In reply to: #33432

> I have come up with three different patches that allow us to work around
> the issue of parent:: being considered an 'explicit class reference' and
> thus disallowing static:: to effectively used.
>
> The patches are against 5.3. I also have patches against HEAD but I was
> having problems getting run-tests.php to run against that code base (it
> would hang on the first test no matter which set of tests I ws running.)
>
> All three patches have different levels of intrusiveness to the engine
> and all three patches have been tested against (and pass) the existing
> lsb tests in Zend/tests/lsb_*.phpt
>
> 1.) lsb.parent-forwarding.patch
> This patch modifies the behavior of only parent:: to not change
> EG(called_class) to the parent of the current scope. With this change.
>
> <?php
>
> class A {
>     public static function test() {
>        echo `get_called_class()`."\n";
>     }
> }
>
> class B extends A {
>     public static function test() {
>        parent::test();
>     }
> }
>
> A::test();
> B::test();
>
> ?>
> will output:
> A
> B
>
> It should be noticed that with this patch parent:: will always resolve
> to the parent of the current scope, it will just not make any changes to
> the called_scope (effectively)

I believe this first patch is the proper way to go. It feels
"natural", "intuitive", etc.

-- 
Alexey Zakhlestin
http://blog.milkfarmsoft.com/

---

## #33435 — Stanislav Malyshev — 2007-11-26T09:26:42+00:00

URL: https://externals.io/message/33290#33435 · In reply to: #33434

> I believe this first patch is the proper way to go. It feels
> "natural", "intuitive", etc.

I don't see how making parent::foo() and A::foo() work differently is 
either "natural" or "intuitive".
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #33437 — Alexey Zakhlestin — 2007-11-26T09:41:28+00:00

URL: https://externals.io/message/33290#33437 · In reply to: #33435

> > […]
>
> I don't see how making parent::foo() and A::foo() work differently is
> either "natural" or "intuitive".

A::foo() doesn't mean any inheritance at all. "A" can be completely
unrelated class

parent::foo() means inheritance and inheritance means "extending" and
"keeping context". So, "parent::foo()" means "call method of
parent-class, but remember, that we extended that class, so keep
context"

-- 
Alexey Zakhlestin
http://blog.milkfarmsoft.com/

---

Next page: https://externals.io/message/33290.md?page=2
