Different instances of static class in PHP
I have this code:
<?php
class Animal {
static public $numLegs;
public static function Walk() {
return 'Takes a step with ' . self::$numLegs . ' legs.';
}
}
class Dog extends Animal {
public static function Init() {
parent::$numLegs = 4;
}
}
class M开发者_运维技巧an extends Animal {
public static function Init() {
parent::$numLegs = 2;
}
}
Dog::Init();
Man::Init();
echo 'The dog walks: ' . Dog::Walk(); //The dog walks: Takes a step with 2 legs.
echo 'The man walks: ' . Man::Walk(); //The man walks: Takes a step with 2 legs.
?>
The problem is that the Animal::$numLegs variable is the same for both. I've tried to make the Animal class not static, but it gives me this error:
"Fatal error: Access to undeclared static property: Animal::$numLegs in..."
I understand that static classes can't be instantiated, but what I want is to have a different 'copy' of the Animal::$numLegs for each of the other static classes (Man and Dog).
How can I do that?
Thanks for your time.
Other answers have already mentioned Late-Static-Binding as the solution to your problem and it is indeed the answer, but nobody has implemented it correctly and some answers have been overly complex.
A static variable is intended to be available to all instances or static accesses of a class in forward-facing fashion. So, as you said in your code, Man was overwriting the value set by Dog because your static variable was set in the parent class, 'Animal', and so was available to each child class. Each child class has access and so can overwrite at any point.
Late static binding solves this by allowing you to have multiple declarations of your static variable in the child classes instead of the parent, but still allowing the parent class to operate on the static variable declared by the child class.
Here is your code, using late static binding properly.
<?php
class Animal {
public static function Walk() {
return 'Takes a step with ' . static::$numLegs . ' legs.'; //the 'static' keyword lets you operate on child classes' static vars
}
}
class Dog extends Animal {
static public $numLegs; //dog has its own static var
public static function Init() {
self::$numLegs = 4;
}
}
class Man extends Animal {
static public $numLegs; //man has its own static var
public static function Init() {
self::$numLegs = 2;
}
}
Dog::Init();
Man::Init();
echo 'The dog walks: ' . Dog::Walk(); //The dog walks: Takes a step with 2 legs.
echo 'The man walks: ' . Man::Walk(); //The man walks: Takes a step with 2 legs.
?>
And the result:
The dog walks: Takes a step with 4 legs.The man walks: Takes a step with 2 legs.
Preface: You need to be using PHP 5.3+ for my example to work. Before PHP 5.3, this sort of stuff was not really possible. The introduction of Late Static Bindings changed that. :)
You can use class constants to achieve the same desired inheritance.
<?php
class Animal {
const NUM_LEGS = 4;
public static function Walk() {
return 'The ' . get_called_class() . ', takes a step with ' . static::NUM_LEGS . " legs.\n";
}
}
class Dog extends Animal {}
class Man extends Animal {
const NUM_LEGS = 2;
}
class Shark extends Animal {
const NUM_LEGS = 0;
}
echo Dog::Walk(); // The Dog, takes a step with 4 legs
echo Man::Walk(); // The Man, takes a step with 2 legs
echo Shark::Walk(); // The Shark, takes a step with 0 legs
Alternatively, if you don't want to use a constant, you can still use a variable. :)
<?php
class Animal {
public static $numLegs = 4;
public static function Walk() {
return 'The ' . get_called_class() . ', takes a step with ' . static::$numLegs . " legs.\n";
}
}
class Dog extends Animal {}
class Man extends Animal {
public static $numLegs = 2;
}
class Shark extends Animal {
public static $numLegs = 0;
}
echo Dog::Walk(); // The Dog, takes a step with 4 legs
echo Man::Walk(); // The Man, takes a step with 2 legs
echo Shark::Walk(); // The Shark, takes a step with 0 legs
You should make use of class inheritance. It is there for a reason: to make your coder nicer and to simplify things. Here is an example:
<?php
class Animal {
protected $numLegs;
protected $name;
public function __construct()
{
$name = 'Animal';
}
public function Walk() {
return 'The ' . $this->name . 'walks: Takes a step with ' . $this->$numLegs . ' legs.';
}
}
class Dog extends Animal {
public function __construct() {
parent::___construct('Dog');
$this->$numLegs = 4;
}
}
class Man extends Animal {
public function __construct() {
parent::___construct('Man');
$this->$numLegs = 2;
}
}
class Turtle extends Animal {
public function __construct() {
parent::___construct('Turtle');
$this->$numLegs = 4;
}
public function Walk() {
return 'The ' . $this->name . 'walks: SLOWLY takes a step with ' . $this->$numLegs . ' legs.';
}
}
$dog = Dog->Init();
$man = Man->Init();
echo $dog->Walk(); //The dog walks: Takes a step with 2 legs.
echo $man->Walk(); //The man walks: Takes a step with 2 legs.
?>
Edit: I have also shown how you can then use this way to create a new class and change the text outputted by Walk() without changing any other class.
精彩评论