PHPEye开源社区 » PHP基础交流 » Web方式下,PHP中的OOP单元本质错位
《Programming PHP》第二版上市
2007-5-4 23:27 diogin
Web方式下,PHP中的OOP单元本质错位

发信人: diogin (说,这段日子会成为回忆), 板面: WebDev
标  题: Web方式下,PHP中的OOP单元本质错位
发信站: 飘渺水云间 (Fri May  4 06:04:26 2007), 站内信件

跟C++之类的OOP语言比较,PHP的OOP单元有它本质的错位。
这种错位导致我一直以来在看基于C++之类语言的面向对象书籍时都觉得不对劲,最
近才真正认识到。。。这种错位只针对web开发方式下的PHP,这种方式下,PHP是从
接收到请求开始,力求最快解释执行完,而非长期驻留的daemon。错位所在地方为:

C++中的static成员,是编译期概念。然而对编程人员而言,PHP并不存在这个阶
段(这个阶段是由Zend引擎直接提供给脚本的),所以实际上在PHP中是不存在类似
C++的static成员这个概念的,PHP中的static成员并不是真正的static。事实上,PHP
中的static成员,是C++中的实例成员,PHP中的类即是C++中的实例!再往上一层,
PHP中的实例,实际上在C++中并没有等价物,可以把它想象成实例的实例。

PHP的一次解释执行,就类似执行C++中的实例的一个方法。PHP中的static生命周期
是一次解释执行,所以PHP的static成员就相当于C++中的实例成员。

而PHP的实例成员,实际上可以想象成实例的实例。基于这种错位调整,目前大多数
PHP框架都没有跟PHP本质对上,在这些框架中存在大量的new,而这种new在PHP中
是根本没必要的。需要new的情况基本上只有一种,就是在一次解释执行中,需要操
作某个领域类的多个对象时。注意,领域类本身实际上就是个对象,所以该领域类
的对象实际上是对象的对象。

PHP技术框架中,应用层的一些类,本质上都是一个个对象。在一次解释执行中,它
们都是单件,多个解释并行起来,才对应上C++里的多个对象。如Dispatcher,
Router,Request,Response,Action,Ajax,View,等等,都是以C++对象形式出
现的PHP类。

幸运的是,在PHP模仿Java的过程中,还是提供了足够的特性让我们基于上述观点来
编写没有错位的框架:PHP的static函数可以是基于类名进行多态的,所以可以进行
传统面向对象编程。需要注意的是,PHP目前没有提供类似“$className::f()”形
式的static多态调用,必须用

call_user_func(array($className, 'f'));

的方式调用。如果需要给f传参数,则用

call_user_func_array(array($className, 'f'), array($var1, $var2));

即可。目前已经有人提交了一个patch,可以直接支持“$className::f()”形式的
调用,希望能被接受并加入语言支持中。可惜的是,abstract static function在
PHP 5.2后已经被归入不合标准的范畴了,只能通过implements一个包含static
方法的interface来绕弯实现传统的多态,实在是遗憾。

另外顺路提一下,提交这个patch的是智利的一位86年的学弟…… orz一下~


--
あの星を集めて この胸に饰りたい
あの梦を繋いで 二人踊った GLAMOROUS DAYS

※ 来源:·飘渺水云间 freecity.cn·[FROM: diogin]

2007-5-4 23:28 diogin
开板第一帖,向大家问个好,哈

2007-5-5 00:53 Haohappy
回复 #1 diogin 的帖子

这不算错位吧,只是解释型语言的OO实现起来和编译型不一样。对于大多数人来说不需要考虑这些,只要能够使用OO的语法来开发就行了,哪种它只是一种表面的形式,是语法糖。

2007-5-5 03:51 diogin
呵呵,还是有开发范式的感觉上的区别的,看看下面的代码:

<?php
interface Static_Command {
    static function run();
}
abstract class Static_Action implements Static_Command {
    final public static function exampleMethodA() {
        echo "example method a\n";
    }
    /**
     * Not allowed! Why?
     */
    abstract public static function exampleMethodB();
}
final class Static_Action_A extends Static_Action implements Static_Command {
    public static function run() {
        self::exampleMethodA();
        self::exampleMethodB();
        echo "running in Static_Action_A\n\n";
    }
    public static function exampleMethodB() {
        echo "example method b, in class Static_Action_A\n";
    }
}
final class Static_Action_B extends Static_Action implements Static_Command {
    public static function run() {
        self::exampleMethodA();
        self::exampleMethodB();
        echo "running in Static_Action_B\n\n";
    }
    public static function exampleMethodB() {
        echo "example method b, in class Static_Action_B\n";
    }
}

$className = 'Static_Action_A';

// native singleton

call_user_func(array($className, 'run'));

/////////////////////////////////////////////////////////

interface Object_Command {
    function run();
}
abstract class Object_Action implements Object_Command {
    final public function exampleMethodA() {
        echo "example method a\n";
    }
    /**
     * This is OK
     */
    abstract public function exampleMethodB();
}
final class Object_Action_A extends Object_Action implements Object_Command {
    public function run() {
        $this->exampleMethodA();
        $this->exampleMethodB();
        echo 'running in object of class ' . get_class($this) . "\n\n";
    }
    public function exampleMethodB() {
        echo "example method b, in Object_Action_A\n";
    }
}
final class Object_Action_B extends Object_Action implements Object_Command {
    public function run() {
        $this->exampleMethodA();
        $this->exampleMethodB();
        echo 'running in object of class ' . get_class($this) . "\n\n";
    }
    public function exampleMethodB() {
        echo "example method b, in Object_Action_B\n";
    }
}

$className = 'Object_Action_B';

// one controller is ok

$object1 = new $className();
$object1->run();

// another controller is bad, singleton pattern is boring

$object2 = clone $object1;
$object2->run();

2007-5-6 12:58 cannot
被 Java 毒害了 :(

2007-5-7 11:20 diogin
这种编程法毕竟不合常理,也比较难看。目前我不打算用这种方式。
不过看看Ruby的面向对象机制,可以感受到多种编程范式间的差异。

2007-9-18 20:32 Matt
感觉以前PHP代码很容易懂,现在看起来比较头大

页: [1]


Powered by Discuz! Archiver 5.5.0  © 2001-2006 Comsenz Inc.