©
이 문서에서는 PHP 중국어 웹사이트 매뉴얼 풀어 주다
本页说明了用 static 关键字来定义静态方法和属性。static 也可用于定义静态变量以及后期静态绑定。参见上述页面了解 static 在其中的用法。
声明类属性或方法为静态,就可以不实例化类而直接访问。静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。
为了兼容 PHP 4,如果没有指定访问控制,属性和方法默认为公有。
由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。
静态属性不可以由对象通过 -> 操作符来访问。
用静态方式调用一个非静态方法会导致一个 E_STRICT
级别的错误。
就像其它所有的 PHP 静态变量一样,静态属性只能被初始化为文字或常量,不能使用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。
自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。
Example #1 静态属性示例
<?php
class Foo
{
public static $my_static = 'foo' ;
public function staticValue () {
return self :: $my_static ;
}
}
class Bar extends Foo
{
public function fooStatic () {
return parent :: $my_static ;
}
}
print Foo :: $my_static . "\n" ;
$foo = new Foo ();
print $foo -> staticValue () . "\n" ;
print $foo -> my_static . "\n" ; // Undefined "Property" my_static
print $foo :: $my_static . "\n" ;
$classname = 'Foo' ;
print $classname :: $my_static . "\n" ; // As of PHP 5.3.0
print Bar :: $my_static . "\n" ;
$bar = new Bar ();
print $bar -> fooStatic () . "\n" ;
?>
</programlisting>
</example>
<example>
<title>静态方法示例</title>
<programlisting role="php">
<![CDATA[
<?php
class Foo {
public static function aStaticMethod () {
// ...
}
}
Foo :: aStaticMethod ();
$classname = 'Foo' ;
$classname :: aStaticMethod (); // 自 PHP 5.3.0 起
?>
[#1] rahul dot anand77 at gmail dot com [2015-11-13 10:39:58]
To check if a method declared in a class is static or not, you can us following code. PHP5 has a Reflection Class, which is very helpful.
try {
$method = new ReflectionMethod( 'className::methodName );
if ( $method->isStatic() )
{
// Method is static.
}
}
catch ( ReflectionException $e )
{
// method does not exist
echo $e->getMessage();
}
*You can read more about Reflection class on http://php.net/manual/en/class.reflectionclass.php
[#2] sideshowAnthony at googlemail dot com [2015-10-02 19:44:05]
The static keyword can still be used (in a non-oop way) inside a function. So if you need a value stored with your class, but it is very function specific, you can use this:
class aclass {
public static function b(){
static $d=12; // Set to 12 on first function call only
$d+=12;
return "$d\n";
}
}
echo aclass::b(); //24
echo aclass::b(); //36
echo aclass::b(); //48
echo aclass::$d; //fatal error
[#3] Ano [2015-02-26 22:42:07]
The doc above says:
"A property declared as static cannot be accessed with an instantiated class object"
But it can, with a double-colon, as shown in the first example (unless I got something wrong).
[#4] ianromie at gmail dot com [2014-07-09 09:18:11]
class A {
public static function getName(){
echo "My Name";
}
public static function getAge(){
return "22";
}
}
A::getName();
echo A::getAge();
[#5] Denis Ribeiro - dpr001 at gmail dot com [2014-03-16 14:23:54]
Other point is that static methods just can access static properties, because the pseudo variable $this not exists in this scope like example below:
<?php
//is wrong, because the static methods can only access static properties
class Foo {
public $property;
public static function aStaticMethod() {
echo "Accessing the property: {$this->property}"; //Fatal error:Using $this
}
}
Foo::aStaticMethod();
$classname = 'Foo';
$classname::aStaticMethod(); // As of PHP 5.3.0
//Note that property $property is static and then can be using the word self instead of pseudo variable $this
class Foo2 {
static $property = 'test';
public static function aStaticMethod() {
echo "Accessing the property: ". self::$property; //Accessing the property: test
}
}
Foo2::aStaticMethod();
[#6] jkenigso at utk dot edu [2013-12-22 00:20:48]
It bears mention that static variables (in the following sense) persist:
<?php
class StaticVars
{
public static $a=1;
}
$b=new StaticVars;
$c=new StaticVars;
echo $b::$a; //outputs 1
$c::$a=2;
echo $b::$a; //outputs 2!
?>
Note that $c::$a=2 changed the value of $b::$a even though $b and $c are totally different objects.
[#7] manishpatel2280 at gmail dot com [2013-11-19 02:45:02]
In real world, we can say will use static method when we dont want to create object instance.
e.g ...
validateEmail($email) {
if(T) return true;
return false;
}
//This makes not much sense
$obj = new Validate();
$result = $obj->validateEmail($email);
//This makes more sense
$result = Validate::validateEmail($email);
[#8] desmatic [2013-11-16 09:40:02]
Don't use GLOBALS in classes (or anywhere really), use static variables instead. They're better. They can do everything a GLOBAL can and they can be protected by accessor functions so they'll never get clobbered.
class foo {
private static $_private = null;
public function get() {
if (self::$_private === null) {
self::$_private = new stdClass();
}
return self::$_private;
}
}
class bar extends foo {
}
function scope_foo() {
$f = new foo();
$f->get()->name = "superdude";
}
function scope_bar() {
$b = new bar();
$b->get()->description = "an object reference test";
}
scope_foo();
scope_bar();
$my = new bar();
foreach ($my->get() as $key => $value) {
echo "{$key} => {$value}\n";
}
outputs:
name => superdude
description => an object reference test
[#9] Anonymous [2013-10-24 01:34:44]
It should be noted that in 'Example #2', you can also call a variably defined static method as follows:
<?php
class Foo {
public static function aStaticMethod() {
// ...
}
}
$classname = 'Foo';
$methodname = 'aStaticMethod';
$classname::{$methodname}(); // As of PHP 5.3.0 I believe
?>
[#10] programmer-comfreek at hotmail dot com [2011-08-08 07:40:31]
If you haven't an instance for your class (e.g. all functions are static), but you also want a __destruct() functionality, consider the following example:
We have a class which loads and saves data so we also want to have an autosave mechanism which is called at the end of the PHP script.
So usually you declare a __destruct function but our class is designed to provide static functions / variables instead:
<?php
class A
{
static private $autoSave;
static public function init($autoSave)
{
self::$autoSave = $autoSave;
}
static public function save() { }
}
?>
In order to define a __destruct function (which is definitely called) we create a new instance in the init() function and define a destruct() function (which is called from the 'real' one):
<?php
class B
{
static private $autoSave;
static public function init($autoSave)
{
self::$autoSave = $autoSave;
new B();
}
static public function destruct()
{
if (self::$autoSave)
self::save();
}
public function __destruct()
{
B::destruct();
}
}
?>
[#11] payal001 at gmail dot com [2011-07-09 03:17:05]
Here statically accessed property prefer property of the class for which it is called. Where as self keyword enforces use of current class only. Refer the below example:
<?php
class a{
static protected $test="class a";
public function static_test(){
echo static::$test; // Results class b
echo self::$test; // Results class a
}
}
class b extends a{
static protected $test="class b";
}
$obj = new b();
$obj->static_test();
?>
[#12] gratcypalma at gmail dot om [2011-04-18 11:50:17]
<?php
class foo {
private static $getInitial;
public static function getInitial() {
if (self::$getInitial == null)
self::$getInitial = new foo();
return self::$getInitial;
}
}
foo::getInitial();
?>
[#13] tolean_dj at yahoo dot com [2010-12-11 17:09:58]
Starting with php 5.3 you can get use of new features of static keyword. Here's an example of abstract singleton class:
<?php
abstract class Singleton {
protected static $_instance = NULL;
final private function __construct() { }
final private function __clone() { }
final public static function getInstance(){
if(null !== static::$_instance){
return static::$_instance;
}
static::$_instance = new static();
return static::$_instance;
}
}
?>
[#14] Mirco [2010-08-23 10:16:38]
The simplest static constructor.
Because php does not have a static constructor and you may want to initialize static class vars, there is one easy way, just call your own function directly after the class definition.
for example.
<?php
function Demonstration()
{
return 'This is the result of demonstration()';
}
class MyStaticClass
{
//public static $MyStaticVar = Demonstration(); //!!! FAILS: syntax error
public static $MyStaticVar = null;
public static function MyStaticInit()
{
//this is the static constructor
//because in a function, everything is allowed, including initializing using other functions
self::$MyStaticVar = Demonstration();
}
} MyStaticClass::MyStaticInit(); //Call the static constructor
echo MyStaticClass::$MyStaticVar;
//This is the result of demonstration()
?>
[#15] Anonymous [2010-06-28 18:49:55]
I can't find anything in the PHP manual about this, but the new-ish E_STRICT error reporting will complain if an inherited class overrides a static method with a different call signature (usually a parameter list). Ironically, it seems to only be a problem of 'coding style' because the code works correctly and has done for quite a few versions.
The exact error is "Strict Standards: Declaration of [child-class]::[method]() should be compatible with that of [parent-class]::[method]()".
So if you must code with E_STRICT enabled, you need to rename the method name.
Google shows that this is biting *a lot* of people. (Bugs have been filed, but there has been no response yet.)
[#16] myselfasunder at gmail dot com [2010-04-13 21:42:53]
If you inadvertently call a non-static method in one class from another class, using $this in the former will actually refer to the wrong class.
<?php
class CalledClass
{
function go()
{
print(get_class($this) . "\n");
return true;
}
}
class CallerClass
{
function go()
{
CalledClass::Go();
return true;
}
}
$obj = new CallerClass();
$obj->go();
// Output is "CallerClass" instead of "CalledClass" like it should be.
?>
Dustin Oprea
[#17] webmaster at removethis dot weird-webdesign dot de [2010-02-25 01:38:46]
On PHP 5.2.x or previous you might run into problems initializing static variables in subclasses due to the lack of late static binding:
<?php
class A {
protected static $a;
public static function init($value) { self::$a = $value; }
public static function getA() { return self::$a; }
}
class B extends A {
protected static $a; // redefine $a for own use
// inherit the init() method
public static function getA() { return self::$a; }
}
B::init('lala');
echo 'A::$a = '.A::getA().'; B::$a = '.B::getA();
?>
This will output:
A::$a = lala; B::$a =
If the init() method looks the same for (almost) all subclasses there should be no need to implement init() in every subclass and by that producing redundant code.
Solution 1:
Turn everything into non-static. BUT: This would produce redundant data on every object of the class.
Solution 2:
Turn static $a on class A into an array, use classnames of subclasses as indeces. By doing so you also don't have to redefine $a for the subclasses and the superclass' $a can be private.
Short example on a DataRecord class without error checking:
<?php
abstract class DataRecord {
private static $db; // MySQLi-Connection, same for all subclasses
private static $table = array(); // Array of tables for subclasses
public static function init($classname, $table, $db = false) {
if (!($db === false)) self::$db = $db;
self::$table[$classname] = $table;
}
public static function getDB() { return self::$db; }
public static function getTable($classname) { return self::$table[$classname]; }
}
class UserDataRecord extends DataRecord {
public static function fetchFromDB() {
$result = parent::getDB()->query('select * from '.parent::getTable('UserDataRecord').';');
// and so on ...
return $result; // An array of UserDataRecord objects
}
}
$db = new MySQLi(...);
UserDataRecord::init('UserDataRecord', 'users', $db);
$users = UserDataRecord::fetchFromDB();
?>
I hope this helps some people who need to operate on PHP 5.2.x servers for some reason. Late static binding, of course, makes this workaround obsolete.
[#18] valentin at balt dot name [2010-01-26 07:46:45]
How to implement a one storage place based on static properties.
<?php
class a {
public function get () {
echo $this->connect();
}
}
class b extends a {
private static $a;
public function connect() {
return self::$a = 'b';
}
}
class c extends a {
private static $a;
public function connect() {
return self::$a = 'c';
}
}
$b = new b ();
$c = new c ();
$b->get();
$c->get();
?>
[#19] Jay Cain [2009-12-18 14:45:05]
Regarding the initialization of complex static variables in a class, you can emulate a static constructor by creating a static function named something like init() and calling it immediately after the class definition.
<?php
class Example {
private static $a = "Hello";
private static $b;
public static function init() {
self::$b = self::$a . " World!";
}
}
Example::init();
?>
[#20] sep16 at psu dot edu [2009-07-10 12:32:57]
I find having class variables useful for inherited classes, especially when inheriting abstract classes, yet self:: doesn't refer to the class calling the method, rather the actual class in which it was defined. Although it is less memory efficient, this can be circumvented with instance properties, but sometimes even this won't work, i.e., when using resources like class-wide database or prepared statement handles.
The pre-5.3.0 way that I used to get around this limitation was to write a class that stores a central value and sets instance properties as references to this value. In this way objects can have access to the same value while still being able to use inherited methods that reference this property.
Usage example:
<?php // (SharedPropertyClass is defined below)
class Foo extends SharedPropertyClass {
public $foo = "bar";
public function showFoo() {
echo $this->foo, "\n";
}
}
class FooToo extends Foo {
public function __construct() {
$this->makeShared('foo');
}
}
$ojjo = new FooToo;
$ojjo->showFoo(); // "bar"
$xjjx = new FooToo;
$xjjx->showFoo(); // "bar"
$ojjo->foo = "new";
$ojjo->showFoo(); // "new"
$xjjx->showFoo(); // "new"
?>
Notice how the showFoo() method, while defined in the parent class, correctly uses the child class's "foo" property (unlike self:: would), and how the "foo" property is shared by all instances of FooToo objects (like a static property). This is essentially how the new static:: keyword will work, and how most people probably expected the self:: keyword to work.
<?php
// ---------------------------------------------------------------
abstract class SharedPropertyClass {
// ---------------------------------------------------------------
private static $shared = array();
public function makeShared($property) {
$class = get_class($this);
if (!property_exists($this,$property))
trigger_error("Access to undeclared property "
. "'$property' in class $class.",E_USER_ERROR);
if (!array_key_exists($class,self::$shared))
self::$shared[$class] = array();
if (!array_key_exists($property,self::$shared[$class]))
self::$shared[$class][$property]
= isset($this->$property)
? $this->$property
: null;
$this->$property =& self::$shared[$class][$property];
}
public function isShared($property) {
$class = get_class($this);
if (!property_exists($this,$property))
trigger_error("Access to undeclared property "
. "'$property' in class $class.",E_USER_ERROR);
return array_key_exists($class,self::$shared)
&& array_key_exists($property, self::$shared[$class]);
}
}
?>
[#21] davidn at xnet dot co dot nz [2009-03-17 16:56:28]
Static variables are shared between sub classes
<?php
class MyParent {
protected static $variable;
}
class Child1 extends MyParent {
function set() {
self::$variable = 2;
}
}
class Child2 extends MyParent {
function show() {
echo(self::$variable);
}
}
$c1 = new Child1();
$c1->set();
$c2 = new Child2();
$c2->show(); // prints 2
?>
[#22] yesmarklapointe at hotmail dot com [2009-01-21 23:19:06]
<?php
// experiments with static
// tested on PHP 5.2.6 on 1-21-09
class User{
const GIVEN = 1; // class constants can't be labeled static nor assigned visibility
public $a=2;
public static $b=3;
public function me(){
echo "print me";
}
public static function you() {
echo "print you";
}
}
class myUser extends User {
}
// Are properties and methods instantiated to an object of a class, & are they accessible?
//$object1= new User(); // uncomment this line with each of the following lines individually
//echo $object1->GIVEN . "</br>"; // yields nothing
//echo $object1->GIVE . "</br>"; // deliberately misnamed, still yields nothing
//echo $object1->User::GIVEN . "</br>"; // yields nothing
//echo $object1->a . "</br>"; // yields 2
//echo $object1->b . "</br>"; // yields nothing
//echo $object1->me() . "</br>"; // yields print me
//echo $object1->you() . "</br>"; // yields print you
// Are properties and methods instantiated to an object of a child class, & are accessible?
//$object2= new myUser(); // uncomment this line with each of the following lines individually
//echo $object2->GIVEN . "</br>"; // yields nothing
//echo $object2->a . "</br>"; // yields 2
//echo $object2->b . "</br>"; // yields nothing
//echo $object2->me() . "</br>"; // yields print me
//echo $object2->you() . "</br>"; // yields print you
// Are the properties and methods accessible directly in the class?
//echo User::GIVEN . "</br>"; // yields 1
//echo User::$a . "</br>"; // yields fatal error since it is not static
//echo User::$b . "</br>"; // yields 3
//echo User::me() . "</br>"; // yields print me
//echo User::you() . "</br>"; // yields print you
// Are the properties and methods copied to the child class and are they accessible?
//echo myUser::GIVEN . "</br>"; // yields 1
//echo myUser::$a . "</br>"; // yields fatal error since it is not static
//echo myUser::$b . "</br>"; // yields 3
//echo myUser::me() . "</br>"; // yields print me
//echo myUser::you() . "</br>"; // yields print you
?>
[#23] zerocool at gameinsde dot ru [2008-10-20 01:06:00]
Hi, here's my simple Singleton example, i think it can be useful for someone. You can use this pattern to connect to the database for example.
<?php
class MySingleton
{
private static $instance = null;
private function __construct()
{
$this-> name = 'Freddy';
}
public static function getInstance()
{
if(self::$instance == null)
{
print "Object created!<br>";
self::$instance = new self;
}
return self::$instance;
}
public function sayHello()
{
print "Hello my name is {$this-> name}!<br>";
}
public function setName($name)
{
$this-> name = $name;
}
}
//
$objA = MySingleton::getInstance(); // Object created!
$objA-> sayHello(); // Hello my name is Freddy!
$objA-> setName("Alex");
$objA-> sayHello(); // Hello my name is Alex!
$objB = MySingleton::getInstance();
$objB-> sayHello(); // Hello my name is Alex!
$objB-> setName("Bob");
$objA-> sayHello(); // Hello my name is Bob!
?>
[#24] wbcarts at juno dot com [2008-10-18 10:24:12]
[NB: This is a copy of the note by juno dot com on 11-Sep-2008 04:53, but with syntax highlighting.]
A CLASS WITH MEAT ON IT'S BONES...
I have yet to see an example that I can really get my chops into. So I am offering an example that I hope will satisfy most of us.
<?php
class RubberBall
{
protected static $count = 0;
protected static $start = 1;
protected static $colors = array('red','yellow','blue','orange', 'green', 'white');
protected static $sizes = array(4, 6, 8, 10, 12, 16);
public $name;
public $color;
public $size;
public function __construct(){
$this->name = 'RB_' . self::$start++;
$this->color = (int) rand(0, 5);
$this->size = self::$sizes[(int) rand(0, 5)];
self::$count++;
}
public static function getCount(){
return self::$count;
}
public static function setStart($val){
self::$start = $val;
}
public static function compare($a, $b){
if($a->color < $b->color) return -1;
else if($a->color == $b->color) return 0;
else return 1;
}
public function __toString(){
return "RubberBall[
name=$this->name,
color=" . self::$colors[$this->color] . ",
size=" . $this->size . "\"]";
}
}
# RubberBall counts the number of objects created, but allows us to
# set the starting count like so:
RubberBall::setStart(100);
# create a PHP Array and initialize it with (12) RubberBall objects
$balls = array();
for($i = 0; $i < 12; $i++) $balls[] = new RubberBall();
# sort the RubberBall objects. PHP's usort() calls RubberBall::compare() to do this.
usort($balls, array("RubberBall", "compare"));
# print the sorted results - uses the static RubberBall::getCount().
echo 'RubberBall count: ' . RubberBall::getCount() . '<br><br>';
foreach($balls as $ball) echo $ball . '<br>';
?>
I'm running out of room so I have not displayed the output, but it is tested and it works great.
[#25] vvikramraj at yahoo dot com [2008-09-23 15:24:57]
when attempting to implement a singleton class, one might also want to either
a) disable __clone by making it private
b) bash the user who attempts to clone by defining __clone to throw an exception
[#26] wbcarts at juno dot com [2008-09-10 20:53:12]
A CLASS WITH MEAT ON IT'S BONES...
I have yet to see an example that I can really get my chops into. So I am offering an example that I hope will satisfy most of us.
class RubberBall
{
protected static $count = 0;
protected static $start = 1;
protected static $colors = array('red','yellow','blue','orange', 'green', 'white');
protected static $sizes = array(4, 6, 8, 10, 12, 16);
public $name;
public $color;
public $size;
public function __construct(){
$this->name = 'RB_' . self::$start++;
$this->color = (int) rand(0, 5);
$this->size = self::$sizes[(int) rand(0, 5)];
self::$count++;
}
public static function getCount(){
return self::$count;
}
public static function setStart($val){
self::$start = $val;
}
public static function compare($a, $b){
if($a->color < $b->color) return -1;
else if($a->color == $b->color) return 0;
else return 1;
}
public function __toString(){
return "RubberBall[
name=$this->name,
color=" . self::$colors[$this->color] . ",
size=" . $this->size . "\"]";
}
}
# RubberBall counts the number of objects created, but allows us to
# set the starting count like so:
RubberBall::setStart(100);
# create a PHP Array and initialize it with (12) RubberBall objects
$balls = array();
for($i = 0; $i < 12; $i++) $balls[] = new RubberBall();
# sort the RubberBall objects. PHP's usort() calls RubberBall::compare() to do this.
usort($balls, array("RubberBall", "compare"));
# print the sorted results - uses the static RubberBall::getCount().
echo 'RubberBall count: ' . RubberBall::getCount() . '<br><br>';
foreach($balls as $ball) echo $ball . '<br>';
I'm running out of room so I have not displayed the output, but it is tested and it works great.
[#27] Mathijs Vos [2008-08-23 03:53:05]
<?php
class foo
{
public static $myStaticClass;
public function __construct()
{
self::myStaticClass = new bar();
}
}
class bar
{
public function __construct(){}
}
?>
Please note, this won't work.
Use self::$myStaticClass = new bar(); instead of self::myStaticClass = new bar(); (note the $ sign).
Took me an hour to figure this out.
[#28] michaelnospamdotnospamdaly at kayakwiki [2008-07-13 18:59:45]
Further to the comment by "erikzoltan NOSPAM at msn NOSPAM dot com" on 05-Apr-2005 03:40,
It isn't just constructors that can't be used for static variable initialization, it's functions in general:
class XYZ
{
static $foo = chr(1); // will fail
}
You have to do external initialization:
XYZ::$foo = chr(1);
class XYZ
{
static $foo;
}
[#29] Siarhei [2008-03-04 05:25:53]
There is a problem to make static property shared only for objects of self class not defining it in every child class.
Example:
class a
{
public static $s;
public function get()
{
return self::$s;
}
}
class b extends a { }
class c extends b { }
a::$s = 'a';
$c = new c();
echo $c->get(); // a
There is solution i found:
class a
{
public final function v($vs = null)
{
static $s = null;
if(!is_null($vs))
$s = $vs;
return $s;
}
}
class b extends a { }
class c extends b { }
$a = new a();
$a->v('a');
$aa = new a();
$aa->v('last a');
$c = new c();
$c->v('c');
echo $a->v().' - '.$c->v(); // last a - c
[#30] inkredibl [2008-01-28 00:27:32]
Note that you should read "Variables/Variable scope" if you are looking for static keyword use for declaring static variables inside functions (or methods). I myself had this gap in my PHP knowledge until recently and had to google to find this out. I think this page should have a "See also" link to static function variables.
http://www.php.net/manual/en/language.variables.scope.php
[#31] ssj dot narutovash at gmail dot com [2008-01-01 20:48:39]
It's come to my attention that you cannot use a static member in an HEREDOC string. The following code
class A
{
public static $BLAH = "user";
function __construct()
{
echo <<<EOD
<h1>Hello {self::$BLAH}</h1>
EOD;
}
}
$blah = new A();
produces this in the source code:
<h1>Hello {self::}</h1>
Solution:
before using a static member, store it in a local variable, like so:
class B
{
public static $BLAH = "user";
function __construct()
{
$blah = self::$BLAH;
echo <<<EOD
<h1>Hello {$blah}</h1>
EOD;
}
}
and the output's source code will be:
<h1>Hello user</h1>
[#32] Clment Genzmer [2007-08-09 01:54:58]
The best solution I found for the non-inherited static problem : pass the name of the class.
<?php
class A {
public static $my_vars = "I'm in A";
static function find($class) {
$vars = get_class_vars($class) ;
echo $vars['my_vars'] ;
}
}
class B extends A {
public static $my_vars = "I'm in B";
}
B::find("B");
// Result : "I'm in B"
?>
[#33] jan(dot)-re-mov.ethis-mazanek/AT-abeo.cz [2006-09-19 23:42:40]
This reacts to comment from
michael at digitalgnosis dot removethis dot com from 16-Dec-2004 08:09
> Note that Base::Foo() may no longer be declared 'static' since static methods cannot be overridden (this means it will trigger errors if error level includes E_STRICT.)
In my test on Windows PHP Version 5.1.4 it seems that it *is possible* to override static method.
This code works at my machine without producing E_STRICT error:
<?php
class Base
{
static function Foo ( $class = __CLASS__ )
{
call_user_func(array($class,'Bar'));
}
}
class Derived extends Base
{
static function Foo ( $class = __CLASS__ )
{
parent::Foo($class);
}
static function Bar ()
{
echo "Derived::Bar()";
}
}
Derived::Foo(); // This time it works.
?>
[#34] Jakob Schwendner [2005-11-04 01:17:05]
Here is my solution to the static search method problem for data objects. I found the debug_trace version posted earlier quite clever, but a little too risky.
<?php
class Foo {
static function find($class) {
$obj = new $class();
return $obj;
}
}
class Bar extends Foo {
static function find() {
return parent::find(__CLASS__);
}
function print_hello() {
echo("hello");
}
}
Bar::find()->print_hello();
?>
[#35] aidan at php dot net [2005-05-04 07:14:10]
To check if a function was called statically or not, you'll need to do:
<?php
function foo () {
$isStatic = !(isset($this) && get_class($this) == __CLASS__);
}
?>
More at (http://blog.phpdoc.info/archives/4-Schizophrenic-Methods.html).
(I'll add this to the manual soon).
[#36] [2005-04-06 03:14:38]
You misunderstand the meaning of inheritance : there is no duplication of members when you inherit from a base class. Members are shared through inheritance, and can be accessed by derived classes according to visibility (public, protected, private).
The difference between static and non static members is only that a non static member is tied to an instance of a class although a static member is tied to the class, and not to a particular instance.
That is, a static member is shared by all instances of a class although a non static member exists for each instance of class.
Thus, in your example, the static property has the correct value, according to principles of object oriented conception.
class Base
{
public $a;
public static $b;
}
class Derived extends Base
{
public function __construct()
{
$this->a = 0;
parent::$b = 0;
}
public function f()
{
$this->a++;
parent::$b++;
}
}
$i1 = new Derived;
$i2 = new Derived;
$i1->f();
echo $i1->a, ' ', Derived::$b, "\n";
$i2->f();
echo $i2->a, ' ', Derived::$b, "\n";
outputs
1 1
1 2
[#37] erikzoltan NOSPAM at msn NOSPAM dot com [2005-04-05 17:50:31]
I was doing this in a more complex example (than previous note) and found that I had to place the initialization statement AFTER the class in a file where I was using the __autoload function.
[#38] erikzoltan NOSPAM at msn NOSPAM dot com [2005-04-05 15:40:44]
I had trouble getting a static member to be an instance of a class. Here's a code example that DOESN'T work.
<?php
// This doesn't work.
class XYZ
{
// The following line will throw a syntax error.
public static $ABC = new ABC();
}
class ABC
{
}
$myXyz = new XYZ();
var_dump($myXyz);
var_dump(XYZ::$ABC);
?>
I get the following entry in my error log.
[05-Apr-2005 18:27:41] PHP Parse error: syntax error, unexpected T_NEW in staticTest.php on line 7
Since PHP doesn't appear to allow static constructor methods, I was only able to resolve this problem by moving the initialization outside of the class. To make my code more self-documenting I put it above the class. The revised example below appears to work.
<?php
// This will work.
// Moved the static variable's initialization logic outside the class.
XYZ::$ABC = new ABC();
class XYZ
{
// I'm just declaring the static variable here, but I'm not initializing it.
public static $ABC;
}
class ABC
{
}
$myXyz = new XYZ();
var_dump($myXyz);
var_dump(XYZ::$ABC);
?>
[#39] michalf at ncac dot torun dot pl [2005-03-31 14:42:09]
Inheritance with the static elements is a nightmare in php. Consider the following code:
<?php
class BaseClass{
public static $property;
}
class DerivedClassOne extends BaseClass{
}
class DerivedClassTwo extends BaseClass{
}
DerivedClassOne::$property = "foo";
DerivedClassTwo::$property = "bar";
echo DerivedClassOne::$property; //one would naively expect "foo"...
?>
What would you expect as an output? "foo"? wrong. It is "bar"!!! Static variables are not inherited, they point to the BaseClass::$property.
At this point I think it is a big pity inheritance does not work in case of static variables/methods. Keep this in mind and save your time when debugging.
best regards - michal
[#40] c_daught_d at earthlink dot net [2005-01-14 13:57:44]
A twist on christian at koch dot net's Singleton example is setting/getting non-static member variables using self::$instance->varname within static method calls.
Within the modified Singleton class below, the member variable $value is set within the getInstance static method instead of the constructor.
Whether this is "pure" OPP, I don't know. But it does work, is worth mentioning, and could be usefull.
class Singleton
{
private static $instance=null;
private $value=null;
private function __construct() {
}
public static function getInstance() {
if ( self::$instance == null ) {
echo "<br>new<br>";
self::$instance = new Singleton("values");
self::$instance->value = "values";
}
else {
echo "<br>old<br>";
}
return self::$instance;
}
}
[#41] ference at super_delete_brose dot co dot uk [2005-01-14 07:11:19]
Both static and const fields can be accessed with the :: operator. However, while a constant can't be changed, this is not true for static variables.
If you want to access an array using the :: operator you have to declare the array static, since you can't have a constant array. Beware:
<?php
class foo
{
static $stuff = array('key1' => 1, 'key2' => 2);
}
class bar
{
public function __construct()
{
var_dump(foo::$stuff);
}
}
class bad
{
public function __construct()
{
foo::$stuff = FALSE;
}
}
new bar(); // prints array(2) { ["key1"]=> int(1) ["key2"]=> int(2) }
new bad();
new bar(); // prints bool(false)
?>
A safe implementation requires a little more effort:
<?php
class foo
{
private static $stuff = array('key1' => 1, 'key2' => 2);
public final static function getstuff()
{
return self::$stuff;
}
}
class bar
{
public function __construct()
{
var_dump(foo::getstuff());
}
}
class bad
{
public function __construct()
{
foo::$stuff = FALSE;
}
}
new bar(); // prints array(2) { ["key1"]=> int(1) ["key2"]=> int(2) }
new bad(); // results in a fatal error
?>
[#42] michael at digitalgnosis dot removethis dot com [2004-12-15 23:41:05]
Here's another way to do the same thing (see my post below) without having to muck up your Foo() function's parameters in the Base and all Derived classes.
However, you cannot use static, and still must define Foo() in derived classes. This way also performs slower and may not always work--but it DOES make for prettier code.
<?php
class Base
{
function Foo ()
{
$call = debug_backtrace();
call_user_func(array($call[1]['class'],'Bar'));
}
}
class Derived extends Base
{
function Foo () { parent::Foo(); }
function Bar ()
{
echo "Derived::Bar()";
}
}
Derived::Foo();
?>
[#43] michael at digitalgnosis dot removethis dot com [2004-12-15 23:09:05]
If you are trying to write classes that do this:
<?php
class Base
{
static function Foo ()
{
self::Bar();
}
}
class Derived extends Base
{
function Bar ()
{
echo "Derived::Bar()";
}
}
Derived::Foo(); // we want this to print "Derived::Bar()"
?>
Then you'll find that PHP can't (unless somebody knows the Right Way?) since 'self::' refers to the class which owns the /code/, not the actual class which is called at runtime. (__CLASS__ doesn't work either, because: A. it cannot appear before ::, and B. it behaves like 'self')
But if you must, then here's a (only slightly nasty) workaround:
<?php
class Base
{
function Foo ( $class = __CLASS__ )
{
call_user_func(array($class,'Bar'));
}
}
class Derived extends Base
{
function Foo ( $class = __CLASS__ )
{
parent::Foo($class);
}
function Bar ()
{
echo "Derived::Bar()";
}
}
Derived::Foo(); // This time it works.
?>
Note that Base::Foo() may no longer be declared 'static' since static methods cannot be overridden (this means it will trigger errors if error level includes E_STRICT.)
If Foo() takes parameters then list them before $class=__CLASS__ and in most cases, you can just forget about that parameter throughout your code.
The major caveat is, of course, that you must override Foo() in every subclass and must always include the $class parameter when calling parent::Foo().
[#44] dmintz at davidmintz dot org [2004-11-09 15:20:04]
[Editor's Note: This is done for back compatability. Depending on your error level, An E_STRICT error will be thrown.]
PHP 5.0.1 doesn't seem to mind if you call a static method in a non-static context, though it might not be the best of style to do so.
On the other hand, PHP complains if you try to try to call a non-static method in a static context (if your error reporting is cranked up to E_STRICT).
class Test {
static function static_method() {
echo "Here's your static method: Foo!<br />\n";
}
function static_method_caller() {
echo "static_method_caller says: ";$this->static_method();
}
function non_static() {
echo "I am not a static method<br />\n";
}
}
$t = new Test();
$t->static_method();
$t->static_method_caller();
Test::non_static();