php手册之static

手册目录: 语言参考---类与对象---static

参考详情: https://secure.php.net/manual/zh/language.oop5.static.php#96402

评论部分:

1. by webmaster@removethis.weird-webdesign.de

在子类中覆盖父类static变量,并调用父类方法对子类的static进行更改,结果不会如预期,如:

<?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();
?>
输出A::$a=lala; B::$a=

使用B::init()却是对A::static的更改,这里A::init()需要将self改成static进行延迟绑定才能达到预期的效果.


2. by davidn@xnet.co.nz

static变量可以在子类间共享,如:

<?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
?>

3. by michael@digitalgnosis.removethis.com

如果你尝试像如下写代码,将会发生fatal error:

<?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()",but sorry,fatal error!
?>

php中的self::只能指向该代码所在类里的属性或者方法,而不是指向实际调用self的类.不能使用__CLASS__代替self,因为它不能出现再::的前面,而且它同self一样不能指向实际调用它的类.

如果你必须要这样坐,你应该使用下面

<?php
class Base
{
    static function Foo ($class = __CLASS__)
    {
        //$class::Bar();
        call_user_func(array($class,'Bar'));
    }
}

class Derived extends Base
{
    function Bar ()
    {
        echo "Derived::Bar()";
    }
}

Derived::Foo('Derived');  //output Derived::Bar()
?>

4. by valentin@balt.name

之前讨论过self指向所在代码类的问题,$this关键字与self不同,它指向调用它的类实例,如:

<?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(); //output b
$c->get();  //output c
?>

class a 的function get()会根据调用类的不同而解释不同的$this.


5. by michael@digitalgnosis.removethis.com

已经知道了在继承的过程中,$this和self的指向性问题,但是针对非静态函数,子类如何调用父类的方法灵活地访问本类属性和父类属性.

首先,对于非静态方法,如果方法中未涉及到针对实例的操作,可以使用class::function来调用

其次,使用回溯函数debug_backtrace()可以记录继承过程中的一些重要信息.如下例:

<?php
class Base
{
    function Foo ()
    {
        $call = debug_backtrace();
       // var_dump($call);
        //echo $call[1]['class']."\n\n";
        call_user_func(array($call[1]['class'],'Bar'));
    }
}

class Derived extends Base
{
    function Foo () { parent::Foo(); }

    function Bar ()
    {
        echo "Derived::Bar()";
    }
}

Derived::Foo();
?>
输出:Derived::Bar()

如果修改成call_user_func(array($call[0]['class','Bar']))将会发生fatal error,此时该函数会调用Base::Bar(),找不到该方法.

在来看看$call到底是什么鬼,var_dump($call):

array(2) {
  [0] =>
  array(6) {
    'file' =>
    string(42) "/home/joker/PhpstormProjects/test/test.php"
    'line' =>
    int(15)
    'function' =>
    string(3) "Foo"
    'class' =>
    string(4) "Base"
    'type' =>
    string(2) "::"
    'args' =>
    array(0) {
    }
  }
  [1] =>
  array(6) {
    'file' =>
    string(42) "/home/joker/PhpstormProjects/test/test.php"
    'line' =>
    int(23)
    'function' =>
    string(3) "Foo"
    'class' =>
    string(7) "Derived"
    'type' =>
    string(2) "::"
    'args' =>
    array(0) {
    }
  }
}

看到没,它将回溯记录父类Base和子类Derived的一些重要信息,其中就包括class,所以我们可以根据$call来灵活调用子类和父类的方法,当然,如果再创建一个类C extends Base,Derived extends C,$call的信息依然不会更改,因为它只是从代码所在类追溯到调用该方法的类,中间经过多少层继承并不关心.

6. by Siarhei

某个类被继承,那么它的static属性也将被"引用继承"(自定义的说法,方便理解,下同)到子类,即子类和父类共同持有该static,他们的任一对static的改变都会互相影响,如:

<?php

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

?>

但是相同的场景,如果是static或非static方法被"复制继承",那么该方法内的static或非static变量在不同的类中将相互独立,所以我们可以这样做:

<?php

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

?>

可以看到此时的类c和类a对function v的操作相互独立.这里function v使用final关键字,可以防止子类对v的覆盖.


7. by sep16@psu.edu

不同类实例 实现共享类public非静态变量,如下:

<?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);
        //var_dump($class);
        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]);
    }
}

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"
?>
如此,$ojjo和$xjjx将共享同一个foo,其中任一对foo的更改都将影响到另一个实例.

8. by Clment Genzmer

另外一种父类访问子类static属性的方法;

<?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"
?>
其实,如果将类B传递过去,就可以直接使用$class::$my_vars来进行调用了,这里仅做为一个不同的方法.


如有错误,请及时联系并及时改正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值