免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2742 | 回复: 4
打印 上一主题 下一主题

[php5][oop][学习笔记]细致学习php5的OO特性[1] [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-08-23 13:38 |只看该作者 |倒序浏览
尽管开发和运行环境早已经是php5了,但是一直没有使用php5的OO特性写代码。现在终于有机会拿着研究C++ OOP的精神,研究PHP5的OO特性。本文设计到一些细节,有些代码仅仅为了测试,有意为之,不要见笑。
(研究的是不是有点晚了,php6都要出来啦^_^)

  • This 伪变量。
从PHP手册中看到这样一句话,一开始有些不理解。
$this 是一个到调用对象(通常是方法所属于的对象,但也可以是另一个对象,如果该方法是从第二个对象内静态调用的话)的引用。

源文档 <http://php.chinaunix.net/manual/zh/language.oop5.basic.php>
于是做了这样的例子:
<?php
   
class ClassB{
        const
NAME = "Class B";
        public   
$a = ClassB::NAME;
        public function
foo(){
            echo
$this->a.":: foo call\n";
            echo
"'this' is a {$this->a} object\n";
        }
    };
   
    class
ClassA{
   
        const   
NAME = "class A";
        public   
$a = ClassA::NAME;

        public function
createB(){
            return new
ClassB();
        }
        
        public  function
foo(){
            echo
$this->a.":: foo call\n";
            
            echo
"\n\nCall a object function\n";
            
$this->createB()->foo();
            
            echo
"\n\n function called statically \n";
            
ClassB::foo();

        }
    }

   
$A = new ClassA();
   
$A->foo();

?>

发现在ClassA里面直接以ClassB::foo();的形式“静态调用”,ClassB::foo();里面的this的确是对象$A的引用。
注意是“静态调用(called statically)”而非静态方法。经过测试,静态方法内不允许this伪变量。
  • Extends
上面的特性-- 在方法被静态调用的上下文环境中,this是调用者的引用,这个特性可以应用到多级继承时,提供子类访问基类的途径:

<?php

   
class BaseClass
   
{
        
// Redefine the parent method
        
public final $abc = "Base";
        function
displayVar()
        {
            echo
"this->abc:".$this->abc."\n";
            echo
"Base class\n";
            
parent::displayVar();
        }
    }

    class
SimpleClass extends BaseClass
   
{
        public
$abc = "SimpleClass";
        
// Redefine the parent method
        
function displayVar()
        {
            echo
"this->abc:".$this->abc."\n";
            echo
"SimpleClass class\n";
        }
    }

    class
ExtendClass extends SimpleClass
   
{
        public
$abc = "ExtendClass";
        
// Redefine the parent method
        
function displayVar()
        {
            echo
"this->abc:".$this->abc."\n";
            echo
"Extending class\n";
            
parent::displayVar();
            
BaseClass::displayVar();
        }
    }

   
$extended = new ExtendClass();
   
$extended->displayVar();
?>


输出:


./test_extends.php
this->abc:ExtendClass
Extending class
this->abc:ExtendClass
SimpleClass class
this->abc:ExtendClass
Base class
  • construct
PHP的__construct不是太严格,甚至允许$obj->__construct , 当然这也可能是为了兼容以前的代码。
但是下面的测试很意外,ClassA::__construct()的调用引起php croe dump了。

<?php
    class ClassAAA{
        function __construct()
        {
            echo "ClassA::__construct\n";
        }
    };
   
    ClassAAA::__construct();
?>
我的php版本:
php -v
PHP 5.2.1 (cli) (built: Apr 28 2007 15:27:26)
Copyright (c) 1997-2007 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2007 Zend Technologies
[2007-09-29更新]:
  php 5.2.4已经更正了这个bug,现在运行
ClassAAA::__construct();会得到一个严重错误:


   Fatal error: Non-static method ClassAAA::__construct() cannot be called statically in /usr/home/duzhigang/php5/test_construct.php on line 10





  • destruct
从手册看到一句话:

  注意: 试图在析构函数中抛出一个异常会导致致命错误。

源文档 <http://php.chinaunix.net/manual/zh/language.oop5.decon.php>
这是因为对象的析构时机依赖php的实际实现,可能在php销毁对象的时候,代码块已经不在我们的try catch控制中了。

对于我下面测试的这个版本,php在一个对象的引用计数为0时,立即调用析构函数进行销毁,所以有幸能捕获到析构函数内的异常。

但是手册里面的这个“注意”是对的,因为php没有明确定义析构函数执行的时机,所以我们不应该在析构函数中抛出异常。
<?php

   
class MyDestructableClass {
        function
__construct() {
            print
"In constructor\n";
            
$this->name = "MyDestructableClass";
        }

        function
__destruct() {
            print
"Destroying " . $this->name . "\n";
            throw new
Exception("my error");
        }
    }


    function
abc(){
        try{
        try{
            
$obj = new MyDestructableClass();
            
//return $obj;
        
}
        catch(
Exception $e){
            echo
"abc::".$e->getMessage();
        }
        }
        catch(
Exception $e){echo "abc::".$e->getMessage();}
        
//echo("abc fun run\n");
   
}

    try{
        
abc();
    }
    catch(
Exception $e){
        echo
"main::".$e->getMessage();
    }
   
   
    try{
        unset(
$r);
    }
    catch(
Exception $e){
        echo
"main 2::".$e->getMessage();
    }
   

?>


【未完待续】


[ 本帖最后由 dulao5 于 2007-9-29 15:47 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-08-23 13:53 |只看该作者
够细致

论坛徽章:
0
3 [报告]
发表于 2007-08-23 14:34 |只看该作者
对于第一个话题,这样理解会好些

namespace::function();

静态调用一个类时,相当于是调用一个有命名空间的函数.那么这个时候$this当然是对调用函数的对象自身的引用.就像对象中调用了一个普通函数那样 ~

论坛徽章:
0
4 [报告]
发表于 2007-08-23 15:34 |只看该作者
原帖由 笨狼追风 于 2007-8-23 16:34 发表
对于第一个话题,这样理解会好些

namespace::function();

静态调用一个类时,相当于是调用一个有命名空间的函数.那么这个时候$this当然是对调用函数的对象自身的引用.就像对象中调用了一个普通函数那样 ~


或者这样理解:

$this 始终指向一个对象实例,因为「静态调用」没有实例,所以,$this 将指向使用「静态调用」的那个对象实例。类似于:


  1. // Pseudo code

  2. function test_this() {
  3.     echo $this->foo;
  4. }
复制代码


哪个对象调用 test_this,那个对象就是 $this。

论坛徽章:
0
5 [报告]
发表于 2007-08-23 15:53 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP