PHP Doku:: Static-Schlüsselwort - language.oop5.static.html

Verlauf / Chronik / History: (1) anzeigen

Sie sind hier:
Doku-StartseitePHP-HandbuchSprachreferenzKlassen und ObjekteStatic-Schlüsselwort

Ein Service von Reinhard Neidl - Webprogrammierung.

Klassen und Objekte

<<Gültigkeitsbereichsoperator (::)

Klassenabstraktion>>

Static-Schlüsselwort

Klassenmember oder -methoden als statisch zu deklarieren macht diese zugänglich, ohne dass man die Klasse instantiieren muss. Auf ein als statisch deklariertes Member kann nicht mit einem instantiierten Klassenobjekt zugegriffen werden (obgleich eine statische Methode dies kann).

Für die Abwärtskompatibilität zu PHP 4 werden Member oder Methode behandelt als ob diese als public static deklariert wären, wenn keine Sichtbarkeit deklariert wird.

Als Initialwerte für statische Eigenschaften können nur Zeichenketten und Konstanten zugewiesen werden, die Zuweisung berechneter Ausdrücke ist nicht möglich. Während also die Initialisierung mit einem Integer oder Array möglich ist können der Wert einer anderen Variablen, der Rückgabewert einer Funktion oder ein Objekt nicht als Initialwert zugewiesen werden.

Weil statische Methoden ohne die Instanz eines erzeugten Objektes aufrufbar sind, ist die Pseudovariable $this nicht innerhalb von der als statisch deklarierten Methode verfügbar.

Auf statische Eigenschaften kann nicht durch das Objekt mittels des Pfeiloperators -> zugegriffen werden.

Unstatische Methoden statisch aufzurufen ruft eine Warnung der Stufe E_STRICT hervor.

Beginnend mit PHP 5.3.0 kann die Klasse über eine Variable referenziert werden. Der Variablenwert kann dabei kein Schlüsselwort (wie self, parent oder static) sein.

Beispiel #1 Beispiel für statische Member

<?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";      // Undefinierte "Eigenschaft" my_static 

print $foo::$my_static "\n";
$classname 'Foo';
print 
$classname::$my_static "\n";

print 
Bar::$my_static "\n";
$bar = new Bar();
print 
$bar->fooStatic() . "\n";
?>

Beispiel #2 Beispiel für statische Methoden

<?php
class Foo {
    public static function 
aStaticMethod() {
        
// ...
    
}
}

Foo::aStaticMethod();
$classname 'Foo';
$classname::aStaticMethod();
?>

38 BenutzerBeiträge:
- Beiträge aktualisieren...
tolean_dj at yahoo dot com
12.12.2010 2:09
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;

   
/**
     * Prevent direct object creation
     */
   
final private function  __construct() { }

   
/**
     * Prevent object cloning
     */
   
final private function  __clone() { }

   
/**
     * Returns new or existing Singleton instance
     * @return Singleton
     */
   
final public static function getInstance(){
        if(
null !== static::$_instance){
            return static::
$_instance;
        }
        static::
$_instance = new static();
        return static::
$_instance;
    }
   
}
?>
Mirco
23.08.2010 19:16
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()
?>
Anonymous
29.06.2010 3:49
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.)
myselfasunder at gmail dot com
14.04.2010 6:42
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
webmaster at removethis dot weird-webdesign dot de
25.02.2010 10:38
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.
valentin at balt dot name
26.01.2010 16:46
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();
?>
Jay Cain
18.12.2009 23:45
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();
?>
maximark at libero dot it
8.12.2009 18:34
<?php
// USING the same method in an instance and in a static context
// If you want to have the same definition of a method that you
// want to use both as static and as instance method, a classname control of $this
// variable is needed. This tip can be used wether the caller context is not the same class type
class A
{
    private
$myProp = 'A';
   
    public function
myMethodA()
    {
        if(isset(
$this) && get_class($this) == __CLASS__)
            return
$this->myProp;
        return
'C';
    }
}
class
B
{
    public
$myProp = 'B';
   
    public function
myMethodB()
    {
       
$a = new A;
        return
$a->myMethodA().'  ++++ '.A::myMethodA();
    }
}
$b = new B();
echo
$b->myMethodB(); // output: A ++++ C

// NOTE:
// if you don't verify "&& get_class($this) == __CLASS__"
// it will output A ++++ B, it seems that if a method is not marked as "static"
// its scope would be the scope in which the function was called
?>
Stratadrake
13.11.2009 21:24
When a method is declared as static, not only is the magic variable $this unavailable (returns NULL), but it is impossible to tell if the function was actually called from a static context.  A backtrace implies that for a static method, calling $object->method() is internally translated to className::method() at run time.

<?php
class Foo
{
  static function
bar()
  {
   
var_dump(reset(debug_backtrace()));
  }
}

$foo = new Foo();

$foo->baz();
Foo::baz();
// Output in either case resembles this:
// array(3)
// {
//   'file' => .....
//   'line => .....
//   'function' => string(3) 'baz'
//   'class' => string(3) 'Foo'
//   'type' => string(2) '::'
// }
?>
sep16 at psu dot edu
10.07.2009 21:32
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 {
// ---------------------------------------------------------------
/*
    Shared properties should be declared as such in the
    constructor function of the inheriting class.

    The first instance will have the shared property set to
    the value in the class definition, if any, otherwise null.
    All subsequent instances will also have their shared
    property set as a reference to that variable.

*/
   
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]);
    }
}
?>
davidn at xnet dot co dot nz
18.03.2009 1:56
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
?>
yesmarklapointe at hotmail dot com
22.01.2009 8:19
<?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
?>
zerocool at gameinsde dot ru
20.10.2008 10:06
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!

?>
wbcarts at juno dot com
18.10.2008 19:24
[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
{
 
/*
   * ALLOW these properties to be inherited TO extending classes - that's
   * why they're not private.
   *
   * DO NOT ALLOW outside code to access with 'RubberBall::$property_name' -
   * that's why they're not public.
   *
   * Outside code should use:
   *  - RubberBall::getCount()
   *  - RubberBall::setStart()
   * These are the only routines outside code can use - very limited indeed.
   *
   * Inside code has unlimited access by using self::$property_name.
   *
   * All RubberBall instances will share a "single copy" of these properties - that's
   * why they're static.
   */
 
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;
  }

 
/*
   * Define the sorting rules for RubberBalls - which is to sort by self::$colors.
   * PHP's usort() method will call this function many many times.
   */
 
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.
vvikramraj at yahoo dot com
24.09.2008 0:24
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
wbcarts at juno dot com
11.09.2008 5:53
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
{
  /*
   * ALLOW these properties to be inherited TO extending classes - that's
   * why they're not private.
   *
   * DO NOT ALLOW outside code to access with 'RubberBall::$property_name' -
   * that's why they're not public.
   *
   * Outside code should use:
   *  - RubberBall::getCount()
   *  - RubberBall::setStart()
   * These are the only routines outside code can use - very limited indeed.
   *
   * Inside code has unlimited access by using self::$property_name.
   *
   * All RubberBall instances will share a "single copy" of these properties - that's
   * why they're static.
   */
  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;
  }

  /*
   * Define the sorting rules for RubberBalls - which is to sort by self::$colors.
   * PHP's usort() method will call this function many many times.
   */
  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.
Mathijs Vos
23.08.2008 12:53
<?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.
nacion_01 at hotmail dot com
22.08.2008 18:38
Thanks to all of you, this is my little contribution, i hope it give you ideas:

The next script uses a class Logs to store and show the logs. You can show the last logs of your scripts. You can:
 - push ("a new log")
 - show () // the last logs until the las call to show()
 - showAll() // to show all the logs and
 - message("a forced message") // which sends a message to the log output with out storing the message (you may imagine other solutions)

<?php
class Logs{
   
// this makes this thing to be hidden from outside calls [private]
   
private static $logs=array("start");
    private static
$index=0;

   
// this is available for outside calls [public]
   
public static function getLogsCount(){
       
// the constant "self" refers to the class, instead $this wich
        // refers to an instance of a class (this class is not instanced,
        // its running itself, so lets use "self" and "::" to access the
        // "static" functions and properties.
       
$count=count(self::$logs);
        return
$count;
    }
    public static function
show(){
       
//echo ("# Logs::show ".self::getLogsCount());
       
$count=self::getLogsCount();
       
// start the show since the last log shown ($index)
       
for ($i=self::$index; $i<$count;$i++){
           
$log=self::$logs[$i];
           
self::message($log);
        }
       
// update the las log shown index
       
self::$index=$i;
    }
    public static function
showAll(){
       
//echo ("# Logs::show ".self::getLogsCount());
        // show the logs from cero to last
        // im starting with php so I use for (...) because its my
        // way in AS3.0 but you better keep checking that
       
$count=self::getLogsCount();
        for (
$i=0; $i<$count;$i++){
           
$log=self::$logs[$i];
           
self::message($log);
        }
    }
   
// Yup! a new log!
   
public static function push($msg){
       
//self::message("# Logs::push ");
       
array_push(self::$logs, $msg);
    }
   
// Send a message to the html output.
    // Now, a little words about this one, you may want to use an
    // special button on your html or somewhere else to show or hide the
    // logs, because you are in development and want to keep this thing
    // little hidden of your clients. Probably may generate a java script
    // variable so instead of [echo "<p>...</p>";] is ok to
    // use [echo "<script>logs+=$msg</script>"]
    // I dont know, figure it out.

   
public function message($msg){
        echo
"<p>- Logs &gt; $msg </p>";
    }
}
// Ready to use.
// to call a function in an static class, refer to the function as
// TheClass::theFunction
// remember, php uses :: (sorry, I still learning why because I come from the AS3 world)

Logs::push("log1");
Logs::show();

Logs::push("log2");
Logs::show();

Logs::push("log3");
Logs::showAll();

?>
michaelnospamdotnospamdaly at kayakwiki
14.07.2008 3:59
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;
}
Siarhei
4.03.2008 14:25
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
inkredibl
28.01.2008 9:27
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
ssj dot narutovash at gmail dot com
2.01.2008 5:48
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>
gabe at mudbugmedia dot com
16.10.2007 15:55
Currently, inheritance with static methods can be a difficult matter, mainly because the 'self' keyword refers the exact class in which the reference is present, much like __CLASS__.  Thus, in a case like the following:

<?php

class A {
    static function
foo () {
        echo
"A::foo()";
    }
   
    static function
callFoo () {
       
self::foo();
    }
}

class
B extends A {
    static function
foo () {
        echo
"B::foo()";
    }
}

B::callFoo();

?>

Will output 'A::foo()' instead of 'B::foo()'.  As of 5.2 and below, there is no clean way to get around this.  get_class(), self, __CLASS__, and even the stack (examined by debug_backtrace()) will all report the appropriate class as being 'A', which is resolved before being called.  There is no sane way, short of determining the filename and line of code from debug_backtrace, re-opening the file, and parsing that out yourself (this kludge is left as an exercise to only the most demented developer).  This setup makes it extremely difficult to develop an ORM like ActiveRecord in PHP.

You'll see some rather ugly solutions below, including passing the class name to callFoo().  Another possible route is to skip static calls all together and make a function that returns an instance of the object, thus allowing you to gain access to the '$this' variable (which *will* know the class name that was originally being called):

<?php
class A {
    static function
foo () {
        echo
"A::foo()";
    }
   
    static function
callFoo () {
       
$this->foo();
    }
}

class
B extends A {
    static function
foo () {
        echo
"B::foo()";
    }
}

function
getB () { return new B(); }

getB()->callFoo();

?>

Luckily, a work around has been committed to PHP's HEAD, and should be available in the 5.3 series.  The concept is called "late static binding" (LSB), and can be read about at http://www.colder.ch/news/08-24-2007/28/late-static-bindings-expl.html .  Basically, you'd have the exact same setup in as in the first example, but instead of calling "self::foo()", you instead would call "static::foo()".
Clment Genzmer
9.08.2007 10:54
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"
?>
james at earthemergency dot org
12.10.2006 13:36
One way to get around the fact that static variables are shared throughout the inheritance tree to map a instance variable to a global variable named after the class.

<?php
$GLOBALS
['static'] = array();
class
root {
  public
$self;
  public static
$all_instances;
 
  function
__construct() {
   
$this->self = &$GLOBALS['static'][get_class($this)];
   
$this->self['instances'] += 1;
   
self::$all_instances     += 1;
  }
}

class
child_a extends root {
}

class
child_b extends root {
}

$a1 = new child_a();
$a2 = new child_a();
$a3 = new child_a();

$b1 = new child_b();
$b2 = new child_b();

echo
"child_a instances: " . $a3->self['instances'] . " | all_instances: " . child_a::$all_instances . "\n";
echo
"child_b instances: " . $b2->self['instances'] . " | all_instances: " . child_b::$all_instances . "\n";

echo
"\$GLOBALS['static'] = ";
var_dump($GLOBALS['static']);
?>

// Output:
child_a instances: 3 | all_instances: 5
child_b instances: 2 | all_instances: 5
$GLOBALS['static'] = array(2) {
  ["child_a"]=>
  &array(1) {
    ["instances"]=>
    int(3)
  }
  ["child_b"]=>
  &array(1) {
    ["instances"]=>
    int(2)
  }
}
jan(dot)-re-mov.ethis-mazanek/AT-abeo.cz
20.09.2006 8:42
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.
?>
Jakob Schwendner
4.11.2005 10:17
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();
?>
aidan at php dot net
4.05.2005 16:14
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).

6.04.2005 12:14
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
erikzoltan NOSPAM at msn NOSPAM dot com
6.04.2005 2:50
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.
erikzoltan NOSPAM at msn NOSPAM dot com
6.04.2005 0:40
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);

?>
michalf at ncac dot torun dot pl
1.04.2005 0:42
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
c_daught_d at earthlink dot net
14.01.2005 22:57
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;
    }
}
ference at super_delete_brose dot co dot uk
14.01.2005 16:11
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
?>
michael at digitalgnosis dot removethis dot com
16.12.2004 8:41
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();

?>
michael at digitalgnosis dot removethis dot com
16.12.2004 8:09
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().
christian at koch dot net
16.11.2004 18:10
STATIC is cool. Here is an example how to get an existing instance as a Singleton:

<?php

class Singleton {

    private static
$instance=null;
    private
$value=null;

    private function
__construct($value) {
       
$this->value = $value;
    }

    public static function
getInstance() {
        if (
self::$instance == null ) {
            echo
"<br>new<br>";
           
self::$instance = new Singleton("values");
        }  else {
            echo
"<br>old<br>";
        }
        return
self::$instance;
    }

}

$x = Singleton::getInstance();
var_dump($x); // returns the new object
$y = Singleton::getInstance();
var_dump($y); // returns the existing object
?>

ckj
dmintz at davidmintz dot org
10.11.2004 0:20
[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();



PHP Powered Diese Seite bei php.net
The PHP manual text and comments are covered by the Creative Commons Attribution 3.0 License © the PHP Documentation Group - Impressum - mail("TO:Reinhard Neidl",...)