静态方法和属性php
静态方法是以类做为做用域
的函数。静态方法不能访问这个类中的普通属性
,由于那些属性属于一个对象
,但能够访问静态属性。若是修改了一个静态属性,那么这个类的全部实例
都能访问到这个新值。
由于是经过类而不是实例来访问静态元素,因此访问静态元素时再也不须要引用对象的变量,而是使用::来链接类名和属性或类名和方法。函数
class StaicExample { static public $aNum = 0; static public function sayHello() { print "hello"; } } print StaicExample::$aNum; StaicExample::sayHello();
一个子类可使用parent
关键字来访问父类,而不使用其类名。要从当前类(不是子类)中访问静态方法或属性,可使用self
关键字。self
指向当前类,就像伪变量$this
指向当前对象同样。所以,在StaticExample
类的外部可使用其类名访问属性$aNum
:this
StaicExample::$aNum;
而在StaicExample
类内部,可使用self
关键字:code
class StaicExample { static public $aNum = 0; static public function sayHello() { self::$aNum++; print "hello (".self::$aNum.")\n"; } }
只有在使用parent
关键字调用方法的时候,才能对一个非静态方法进行静态形式的调用(使用::
)。除非是访问一个被覆写的方法,不然永远只能使用::
访问被明确声明为static
的方法或属性。有时看到使用static
语法来引用方法或属性,可能并不意味着其中的方法或属性必须是静态的,只不过说明它属于特定的类。对象
根据定义,不能在对象中调用静态方法。所以静态方法和属性又被称为类变量和属性
,也就不能在静态方法中使用伪变量$this
。继承
为何要使用静态方法或属性呢?作用域
延迟静态绑定:static关键字
静态方法能够用做工厂方法,工厂方法是生成包含类的实例的一种方法。
先看下面的重复代码:get
abstract class DomainObject { } class User extends DomainObject { public static function create() { return new User(); } } class Document extends DomainObject { public static function create() { return new Document(); } }
想必你们都不想为每一个DomainObject
子类都建立与上面代码相似的标准代码。若是把create()
放在超类呢?io
abstract class DomainObject { public static function create() { return new self(); } } class User extends DomainObject { } class Document extends DomainObject { } Document::create();
这回看起来简洁多了。如今把常见的代码放在一个位置,并使用self
做为对该类的引用。实际上,self对该类所起的做用与$this对对象所起的做用并不彻底相同。self指的不是调用上下文,而是解析上下文
。所以,运行刚才上面的代码会获得:function
PHP Fatal error: Cannot instantiate abstract class DomainObject in ...
所以,self被解析为定义create()的DomainObject,而不是解析为调用self的Document类
。PHP5.3以前,在这方面有严格的限制,产生不少笨拙的解决方案。PHP5.3引入了延迟静态绑定
的概念。该特性最明显的标志就是新关键字static。static相似于self,但它指的是被调用的类而不是包含类
。
在本例中,它的意思是调用Document::create()将生成一个新的Document对象,而不是试图实例化一个DomainObject对象。
所以,如今在静态上下文使用继承关系。
abstract class DomainObject { public static function create() { return new static(); } } class User extends DomainObject { } class Document extends DomainObject { } print_r(Document::create());//Document Object {}
static关键字不单单能够用于实例化。和self和parent同样,static还能够做为静态方法调用的标识符,甚至是从非静态上下文中调用。
若是想为DomainObject引入组(group)的概念。默认状况下,全部类都属于default类别,但想能够为继承层次结构的某些分支重写类别。
abstract class DomainObject { private $group; public function __construct() { $this->group = static::getGroup(); } public static function create() { return new static(); } static function getGroup() { return "default"; } } class User extends DomainObject { } class Document extends DomainObject { static function getGroup() { return "document"; } } class SpreadSheet extends Document { } print_r(User::create()); print_r(SpreadSheet::create());
在DomainObject类中定义了构造函数。该构造函数使用static关键字调用静态方法getGroup()。DomainObject提供了默认实现,但Document将其覆盖了。建立的SpreadSheet新类扩展了Document类。下面是打印结果:
User Object ( [group:DomainObject:private] => default ) SpreadSheet Object ( [group:DomainObject:private] => document )
最后根据本身的理解,写个例子:
<?php class Model { protected $model; public function __construct() { $this->model = static::getModel(); //延迟绑定 } public function __get($name) { return $this->{'get'.ucfirst($name)}(); } public static function getModel() { return 'Model'; } public function getModelName() { return $this->model; } public function __toString() { return $this->modelName; } } class User extends Model { public static function getModel() { return 'User'; } } class Book extends Model { public static function getModel() { return 'Book'; } } $model = new Model; $user = new User; $book = new Book; echo $model . PHP_EOL; // Model echo $user . PHP_EOL; // User echo $book . PHP_EOL; // Book
当把Model类的构造方法中的static::getModel()改成self::getModel()后:
echo $model . PHP_EOL; // Model echo $user . PHP_EOL; // Model echo $book . PHP_EOL; // Model