Until last week, I had never experienced what must have been incredibly frustrating to most developers: the fact that the self keyword in PHP refers to the class it is located in, and not necessarily a class that extends it. I personally ran into this problem when trying to extend Zend_Auth. Being a singleton, the constructor in Zend_Auth is protected, and the static method Zend_Auth::getInstance() instantiates itself. The problem is, when extended, My_Auth::getInstance() still returns an instance of Zend_Auth. The solution was to duplicate the static method in my My_Auth class, which worked properly. For example:
1.
2.
3.
class
My_Auth
extends
Zend_Auth
4.
{}
5.
6.
echo
get_class(My_Auth::getInstance());
What did I get as a return value? Zend_Auth – because here is the source code of the getInstance() method in Zend Framework’s Zend_Auth class:
01.
/**
02.
* Returns an instance of Zend_Auth
03.
*
04.
* Singleton pattern implementation
05.
*
06.
* @return Zend_Auth Provides a fluent interface
07.
*/
08.
public
static
function
getInstance()
09.
{
10.
if
(null === self::
$_instance
) {
11.
self::
$_instance
=
new
self();
12.
}
13.
14.
return
self::
$_instance
;
15.
}
Why didn’t I get an instance of My_Auth instead of Zend_Auth? Well, that’s because PHP determines the meaning of the self keyword at compile time, meaning that when you call a function that makes use of it later, you’ll get whatever it’s been defined to mean when it was compiled.
PHP 5.3 provides a workaround for this, called late static binding. Simply put, PHP 5.3 introduces a new use of the keyword static, that allows you to avoid this define-at-compile-time problem. Using PHP 5.3 with the same example, and the static keyword, here is what happens.
01.
// Auth.php rewritten
02.
03.
/**
04.
* Returns an instance of Zend_Auth
05.
*
06.
* Singleton pattern implementation
07.
*
08.
* @return Zend_Auth Provides a fluent interface
09.
*/
10.
public
static
function
getInstance()
11.
{
12.
if
(null ===
static
::
$_instance
) {
13.
static
::
$_instance
=
new
static
();
14.
}
15.
16.
return
static
::
$_instance
;
17.
}
18.
19.
// My Auth class and sample code
20.
class
My_Auth
extends
Zend_Auth
21.
{}
22.
23.
echo
get_class(My_Auth::getInstance());
The result here is now that an instance of My_Auth is returned. Late static bindings make working with static methods much easier. For this feature alone I believe PHP 5.3 is a worthwhile upgrade.
The original work of Brandon Savage.
No comments:
Post a Comment