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

  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(); //在类的外部:静态访问方式不能访问非静态方法。。。但是菲静态访问方式可以访问静态方法。。。

列出几个问题:

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

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

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

  1. class Foo
  2. {
  3. public static $name = 'so ga';
  4. public function _foo()
  5. {
  6. echo self::$name;
  7. }
  8. }
  9.  
  10. $foo = new Foo;
  11. print $foo::$name;
  12. $foo::_foo(); //调用可以输出值,,但是会报一个E_STRICT 级别的错误,,不会终止程序执行。。
  13. $foo->_foo();

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

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

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

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

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

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

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

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

  1. class Test
  2. {
  3. private static $instance ;
  4.  
  5. // construct 设置成私有
  6. public function __construct()
  7. {
  8. if(self::$instance === null){
  9. self::$instance = 888;
  10. }
  11. return self::$instance;
  12. }
  13.  
  14. public static function visit()
  15. {
  16. echo '<hr>';
  17. echo 'ok';
  18. echo self::$instance;
  19. echo (new self)->aaa();
  20. echo '<hr>';
  21. }
  22.  
  23. public function aaa()
  24. {
  25. echo __METHOD__;
  26. echo self::$instance;
  27. }
  28. }
  29. $t3 = Test::visit(); //输出的结果不一样,output:okTest::aaa888
  30. $t3 = Test::visit(); //output:ok888Test::aaa888
  31. $t3 = Test::visit();

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

  1. class Test
  2. {
  3. private static $instance ;
  4.  
  5. // construct 设置成私有
  6. public function __construct()
  7. {
  8. if(self::$instance === null){
  9. self::$instance = 888;
  10. }
  11. return self::$instance;
  12. }
  13.  
  14. public static function visit()
  15. {
  16. echo '<hr>';
  17. echo 'ok';
  18. echo self::$instance;
  19. echo (new self)->aaa();
  20. echo '<hr>';
  21. }
  22.  
  23. public function aaa()
  24. {
  25. echo __METHOD__;
  26. echo self::$instance;
  27. }
  28. }
  29.  
  30. $t = new Test;
  31. $t->visit();

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

PHP关于对象访问静态方法、属性等问题的更多相关文章

  1. JavaScript对象访问器属性

    对象访问器就是setter和getter,他们的作用就是 提供另外一种方法来获取或者设置对象的属性值, 并且在获取和设置的时候,可以用一定的其他操作. 看下面代码: <script> va ...

  2. javascript中对象访问自身属性的方式

    在javascript中,通过对象的方法访问对象自身属性时,必须采用this.fieldName的方式. 原因是javascript中Function是无状态的,访问对象的属性时,必须指定当前的上下文 ...

  3. 007-对象—— static静态方法属性内存构成及使用方法讲解

    <?php /* 7 对象 static静态方法属性内存构成及使用方法讲解 */ /*class a{ public $uname=11; static public function _a() ...

  4. JavaScript | 数据属性与访问器属性

    属性类型 数据属性 - 包含一个数据值的位置,可以读取和写入值 [writable] 是否能修改属性的值 true [enumerable] 是否通过for in 循环返回属性(是否可以被枚举) tr ...

  5. python中类对象、实例对象、类属性、实例属性、类方法、实例方法、静态方法

    类对象.类属性与实例对象.实例属性的区别 在Python中一切皆是对象,类是一个特殊的对象即类对象,描述类的属性称为类属性.类属性在内存中只有一份,在__init__外部定义. 通过类创建的对象称为实 ...

  6. 在实体对象中访问导航属性里的属性值出现异常“There is already an open DataReader associated with this Command which must be closed first”

    在实体对象中访问导航属性里的属性值出现异常“There is already an open DataReader associated with this Command which must be ...

  7. javascript对象属性——数据属性和访问器属性

    ECMA-262第五版在定义时,描述了属性property的各种特征,定义这些特性是为了实现javascript引擎用的,为了表示该特性是内部值,规范把它们放在了两对儿方括号中,例如[[Enumera ...

  8. 类实例化对象可以访问静态(static)方法,但是不能访问静态属性。

    类-> 访问->静态方法(类的方法)->可以 类 ->访问->普通方法(对象的方法)->不可以(虽然方法里不用$this关键字时,可以!但不支持这种写法) 类-&g ...

  9. js对象的数据属性和访问器属性

    js面向对象 ECMA-262第5版在定义只有内部才用的特性(attribute)时,描述了属性(property)的各种特征.ECMA-262定义这些特性是为了实现javascript引擎用的,因此 ...

随机推荐

  1. [转帖]流言终结者 —— “SQL Server 是Sybase的产品而不是微软的”

    流言终结者 —— “SQL Server 是Sybase的产品而不是微软的” https://www.cnblogs.com/xxxtech/archive/2011/12/30/2307859.ht ...

  2. Django在使用Mysql迁移数据库时,会报的错

    settings : DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'firstproject', ...

  3. Dango之视图函数

    1.request对象 HTTPRequest对象就是咱们的视图函数的参数request def home(request): print(request) #<WSGIRequest: GET ...

  4. python面向对象反射-框架原理-动态导入-元类-自定义类-单例模式-项目的生命周期-05

    反射 reflect 反射(reflect)其实是反省,自省的意思 反省:指的是一个对象应该具备可以检测.修改.增加自身属性的能力 反射:通过字符串获取对象或者类的属性,进行操作 设计框架时需要通过反 ...

  5. 不基于比较的排序算法:Counting-sort和Radix-sort

  6. HDFS NFS Gateway

    NFS网关支持NFSv3,并允许将HDFS作为客户端本地文件系统进行挂载.目前,NFS Gateway支持并启用以下使用模式: 用户可以通过NFSv3客户端兼容操作系统上的本地文件系统浏览HDFS文件 ...

  7. 使用iview 的表单组件验证 Upload 组件

    使用iview 的表单组件验证 Upload 组件 结果: 点击提交按钮, 没有填的form 项, 提示错误, 当填入数据后提示验证成功 代码: <template> <div id ...

  8. Django框架——进阶之AJAX

    <script>$("#b1").on("click", function () { // 点击 id是b1的按钮要做的事儿 var i1 = $( ...

  9. scrapy-redis 实现分布式爬虫

    分布式爬虫 一 介绍 原来scrapy的Scheduler维护的是本机的任务队列(存放Request对象及其回调函数等信息)+本机的去重队列(存放访问过的url地址) 所以实现分布式爬取的关键就是,找 ...

  10. 本地安装Mysql后,navicat链接异常:Clinet dose not support authentication protocol request by server ; consider upgrading MySQL client

    第一步:首先通过cmd进入mysql 在命令窗口 输入:mysql -u root -p: 第二步:更改加密方式 mysql> ALTER USER 'root'@'localhost' IDE ...