百度首页 | 百度空间
 
查看文章
 
What are you doing for?
2008年06月25日 星期三 09:49 A.M.
一直以来,感觉搞技术就要虚心、认真,并且负责任!

当然每个人的成长阶段不同,难免出现差别,但这也不能掩盖基本的要求。

早上看到一篇博文,题目:“为什么子类重写父类方法时访问权限不能比父类低?”。

看到这个标题就是一惊,因为PHP中当子类重写父类方法时,其访问权限必须”小于或等于 =》 大于或等于“父类中此方法的访问权限。(PS:是我错了)

出于好奇心,继续看博主的文章,将他的例子摘录过来:

  1. class b {   
  2.     public function __construct() {   
  3.         //   
  4.      }   
  5. }   
  6.   
  7. class a extends b {   
  8.     private static $instance = NULL;   
  9.        
  10.     private function __construct() {   
  11.          parent::__construct();   
  12.      }   
  13.        
  14.     public static function getInstance() {   
  15.         if (self::$instance === NULL) {   
  16.              self::$instance = new a();   
  17.          }   
  18.         return self::$instance;   
  19.      }   
  20.        
  21.     public function test() {   
  22.         echo "success";   
  23.      }   
  24. }   
  25.   
  26. $foo = a::getInstance();   
  27. $foo->test();

这下倒好,错的不仅是标题,连基本的知识都错了。

在PHP手册中显著的注明了一条:PHP中的__construct()构造函数必须为”public“类型,因为当类被初始化时自动调用__construct()构造函数,这被看做是外部访问。(按照留言,如果是做单件用,我又错了)

错误人人都会有,也许你会觉得不应该写文章来讨论此问题。毕竟学习成长是一个艰苦的过程,需要的不仅仅是自己的毅力,同样需要他人的鼓励和帮助。

但是,如果你看到博主下面的文字,就会觉得我们应该来说些什么,对于博主,对于自己,对于他人。

现有一个类b,他用a继承b类,他又希望a的所有实例能保持单一,所以他打算让a类实现单例模式(关于单例模式以后会专门写一篇文章讨论,如果你不懂这个概念,请直接搜索)。此想法似乎没有任何不妥之处,然后代码运行之后,程序报了错:

Fatal error: Access level to a::__construct() must be public (as in class b) in E:\website\test.php on line 29

为什么编译器会报这样的错误?这是因为子类重写父类方法的时候,其访问权限不能比父类低,这意味着:

  1. 如果父类的某方法是public类型,则子类中此方法也必须是public
  2. 如果父类的某方法是protected类型,则子类中此方法可以是protected或则public
  3. 如果父类的某方法是private类型,则子类中此方法可以是任意类型。

可是为什么编译器要做这样的限制?这涉及到一个面向对象设计的基础性原则:里矢代换原则(LSP)

    如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都被带换成o2时,程序P的行为没有变化,那么类型T2是类T1的子类型。

也就是说,一个软件实体如果使用的是一个基类的话,那么一定适合于其子类,而且它根本不能察觉出基类对象和子类对象的区别。里矢代换原则是继承复用的基石,它是依赖倒转原则(DIP)必须遵循的基本原则,而依赖倒转原则则是实现开放封闭原则(OCP)的主要机制。这即是面向对象三大基本原则的关系。

    所以在编译器编译程序的时候,它会去检查一个程序是否符合里矢代换原则,当然这是一个无关业务逻辑,只是简单的语意上的检查。里矢代换原则要求凡是基类型 使用的地方,子类型也一定适用,因此子类必须具备基类型的全部接口。或则说,子类的接口必须包括基类的全部接口,可以再其基础上更宽,但是不能更窄。所以 我们从里矢代换原则来思考本文标题提出的问题,那么就很简单了,b的构造函数__construct()是public类型,而a的构造函数因为要实现单 例模式所以变成了private类型,因此编译器不会让其通过的。

近乎高深的解释(PS:反正我不懂他哪来的这么多高深理论):从PHP脚本错误,到面向对象,再到编译器,最后是软件设计,可谓”洋洋而谈“。

如果这在我大学时代,也许我会马上打开google,按照他所说的依次搜索“面向对象” -> ”面向对象设计的基础性原则“ -> ”里矢代换原则“(PS:也许这里google会提示你要找的是不是"里氏代换原则”)-> "依赖反转“ ... 哎,足够多了!

现在你应该看到博主有多么的***让我写这篇文章了吧?

以前总有人说:国内的IT开发气氛有多么的不好,开发人员态度有多么的不端正。

也许这只是一个小小的例子,但需要更多的人去帮助,让这种心态放平稳。

工作固然重要,但对待工作的心态尤其重要。

附注:最后的结论是我错了,在此向博主道歉!

类别:php.mastery | 添加到搜藏 | 浏览() | 评论 (5)
 
最近读者:
 
网友评论:
1
2008年06月25日 星期三 01:23 P.M.
我对你无语了。。
自己的基本功不够,还要批判别人。。
自己好好补习一下面向对象基础。。
特别是看看单例模式。。
 
2
2008年06月25日 星期三 01:40 P.M.
构造函数写成private是为了不让使用者实例化该类的对象,可以调用静态方法来操作
 
4
2008年06月25日 星期三 01:56 P.M.
多谢你们的指教o(∩_∩)o...哈哈

最后的结论是我错了,在此向博主道歉!
 
5
2008年06月25日 星期三 02:02 P.M.
没关系
探讨交流才能进步
 
6
2008年06月25日 星期三 02:32 P.M.
多交流才能提高..哈哈..
 
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码:
 

     

©2008 Baidu