为何有这样的问题呢?源自一段代码,如下:

 1 class A
 2 {
 3     // public static $name = 'wangyumeidsb';
 4 
 5     public $name = 'woaini';
 6 
 7     public static function foo()
 8     {
 9         echo __CLASS__;
10     }
11 
12     public function test()
13     {
14         self::foo();
15         echo '---'; 
16         $this->foo();
17         echo '<hr>';
18         // echo 'this is A<br>'."\n";
19     }
20 
21     public function say()
22     {
23         echo '我是非静态方法';
24     }
25 }
26 
27 class B extends A
28 {
29     public  function who()
30     {
31         A::test();
32         A::foo();
33         // echo A::$name;
34         echo $this->name;    //
35         parent::test();
36         self::test();
37         $this->test();   //self并不是必须调用static,非静态也能调用?
38     }
39 }
40 
41 // A::say();
42 $b = new B;
43 $b->who();
44 // echo 'this is non-static property'.$b->name.'<br>';
45 // echo A::$name;
46 echo '>>>>>>>>>>>>>>>>';
47 $a = new A;
48 $a->test();
49 $a->foo();
50 A::foo();
51 
52 // A::test();    //在类的外部:静态访问方式不能访问非静态方法。。。但是菲静态访问方式可以访问静态方法。。。
View Code

列出几个问题:

  1. 为何可以使用A::test();这种方式访问非静态方法test()?
  2. self::test();虽然说B要继承A的test方法,但是test不是静态方法,不归类所有,为何这种方式也可以访问?self不是必须访问静态成员吗,也可以访问非静态?那self指向的是什么?

手册说明   : 静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。就像其它所有的 PHP 静态变量一样,静态属性只能被初始化为文字或常量,不能使用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。

在手册中看到了一个以前不知道的访问方式--------可以使用$foo::$name;来调用静态属性。$foo是对象啊!

class Foo
{
    public static $name = 'so ga';
    public function _foo()
    {
        echo self::$name;
    }
}  

$foo = new Foo;
print $foo::$name;
$foo::_foo();  //调用可以输出值,,但是会报一个E_STRICT 级别的错误,,不会终止程序执行。。
$foo->_foo();
View Code

 

我把A::  称为静态访问方式,把$a->  称为非静态访问方式。下面都这样理解。

总结:在类的外部,静态访问方式可以访问静态方法,不能访问非静态方法(能够执行,但是用静态方式调用一个非静态方法会导致一个 E_STRICT 级别的错误。);非静态访问方式既可以访问静态方法,又可以访问非静态方法。

           静态访问方式可以访问静态属性,不可以访问非静态属性;非静态访问方式可以访问非静态属性,不能访问静态属性。

    在类的内部,静态访问方式既可以访问静态方法又可以访问非静态方法;非静态访问方式既可以访问静态方法,又可以访问非静态方法。

         静态访问方式只能访问静态属性,不可以访问非静态属性;非静态访问方式可以访问非静态属性,不能访问静态属性。

更新:看到了鸟哥的一篇博客http://www.laruence.com/2012/06/14/2628.html    (尽量要避免使用”::”来调用一个非静态的方法)

附加:在手册中看到的一句话,同一个类的对象即使不是同一个实例也可以互相访问对方的私有与受保护成员。这是由于在这些对象的内部具体实现的细节都是已知的。(访问控制

——————————————————更新补充——————————————————

 

class Test
{
    private static $instance ;

    // construct 设置成私有
    public function __construct()
    {
        if(self::$instance === null){
            self::$instance = 888;
        }
        return self::$instance;
    }

    public static function visit()
    {
        echo '<hr>';
        echo 'ok';
        echo self::$instance;
        echo (new self)->aaa();
        echo '<hr>';
    }

    public function aaa()
    {
        echo __METHOD__;
        echo self::$instance;
    }
}
$t3 = Test::visit(); //输出的结果不一样,output:okTest::aaa888
$t3 = Test::visit(); //output:ok888Test::aaa888
$t3 = Test::visit();
View Code

 

为什么两次调用静态方法输出结果不同,分析了一下:因为调用静态方法不会触发构造函数,所以第一次没有执行到new操作的时候,静态属性$instance没有值。然后new self就调用了构造函数,初始化了$instance,而$instance是归类所有的。所以当第二次调用静态方法的时候,他就有值了。所以输出888。

class Test
{
    private static $instance ;

    // construct 设置成私有
    public function __construct()
    {
        if(self::$instance === null){
            self::$instance = 888;
        }
        return self::$instance;
    }

    public static function visit()
    {
        echo '<hr>';
        echo 'ok';
        echo self::$instance;
        echo (new self)->aaa();
        echo '<hr>';
    }

    public function aaa()
    {
        echo __METHOD__;
        echo self::$instance;
    }
}


$t = new Test;
$t->visit();
View Code

而像这种实例化对象来访问静态方法,在实例化的时候就已经触发了构造函数,所以第一次访问$instance就有值。