Oracle Technology Network (OTN) > Downloads, Discussions, and Documentation for Developers and DBAs

Philippe Lachaise 开放源代码

从 C++ 到 PHP
作者:Philippe Lachaise

具备较强的 C++ 使用经验可以为您学习 PHP 脚本编写提供重要帮助。相反,如果对 PHP 采用比较简单的方法,那么在事情变得复杂时,您将遇到麻烦。

“为什么要浪费时间去涉猎 PHP?”

不久前,我的一个朋友,也是我以前的同事曾问过我这个问题。他的看法反映了一个仍然比较普遍的认识:尽管 PHP 获得成功,但它并不是一种正式的语言,至少它不适合于企业应用程序开发。

在我们共事期间,大家都称我为内部 C++ 专家。在我朋友看来,以往使用 C++ 的我现在却如此专注于 PHP,这显得有些不合乎情理,他认为我应该把精力放在 Java 或 .NET(或者两者兼而有之)的研究上。

不受营销宣传的影响有时会帮助我们发现一个重要的现象。PHP 普及程度的提升就是一个例子。具备较强的 C++ 使用经验可以为学习 PHP 脚本语言提供重要帮助,这听起来很让人感到不解

网络最终将演化为计算机

长期以来仅仅留于口号的这个著名标语现已成为事实。人们已经认识到,将互联网技术应用于各种网络应用程序可以获得很多好处,如果丰富客户端仍是一种可选方法,它们将基于新的 Web 技术构建。下面让我们诠释一下软件开发的含义。

暂时将真正的分布式应用程序和 Web 服务放在一边,以通常的动态网站为例,它实际上是我们非常熟悉的客户端-服务器应用程序在互联网上的一种转化。

重新启动并不可取:由于访问者日夜不停的访问网站,因此不允许应用程序代码出现崩溃。它可以生成错误(这是一种客观现象),但却不能崩溃。这种情况下,C++ 并不适合于 Web 开发。我并不是说我不会尝试这样做,而是不会相信任何人会这样做。归根结底,这种做法是不切合实际的。

编码器又有了用武之地

现在,随着 IT 就业市场从 PC 快速转向 Web,我如何继续使用辛辛苦苦才积累起来的 C++ 对象编程专业技能?

PHP 为我创造了这样的机会。起初看来,脚本语言值得怀疑。对于习惯使用编译器的人而言,脚本就像玩具一样。松散类型将导致变量全方位变形,而这必然是一个非常缓慢的过程....

再仔细想想,Web 的汇编语言不再是二进制代码,而是文本标记。而文本需要脚本。

随后一个比较迫切的问题是:如何将编译语言方面的所有宝贵专业技能重新应用于以脚本为主导的环境中?

因此,让我们忘记偏见并对其进行一试。我们不会放弃对象方法学。每当我通过重新使用快速粗略的编码尝试一种简捷的方法时,最终还是必须要回溯并再次创建对象。因此,满足对象支持将成为一个不成则败的条件。

最初阶段:Do-Re-Mi

正如这首歌曲所唱的那样,我们需要从一个不错的起点开始操作。下面让我们编写一个类:

class MyClass // C++ like comments are supported
{
}

还记得么?C++ 将报告缺少分号,但这并不要紧。好的,我们现在已经创建了一个类;下面我们将对其加以介绍,同时指出差别和相似点。大多数差别仅仅体现在语法方面,而只有少数几个差别需要进行深入介绍。

为了使事情变得简单,我们将只对 PHP4 进行分析。

// Notice "extends" keyword. All inheritance is public anyway. 
class MyClass extends BaseClass
{
 var $_dow; // For some historical reasons class
 var $_ray; // attributes are declared with "var"
 var $_me;  // keyword (ours is not to reason why)

 // Constructor, like in C++ is a function named like class
 // "function" keyword is mandatory. No return type.
 function MyClass($param) 
 {
  // Explicit call to parent class constructor
  $this->BaseClass($param);
 }

 // There is no ~MyClass()

 // Return types are not specified, reference (&) is.
 function & get_note($note)
 {
  // We assume $note is a string (could check with is_string())
  switch ($note) // Highly familiar switch statement...
  {
   case 'dow': // ... apart from its understanding strings !
    return $this->_dow;
   case 'ray':
    return $this->_ray;
   case 'me':
    return $this->_me;_me;
   default:
    break;
  }
  // Undefined return values are your responsibility ! 
 }
}

起初,语法方面的差别可能令人感到不快,但这很快就会消失。您必须记住 PHP 将被解释,因此如果“$”前缀加快变量查找,或者必须使用 $this-> 来消除局部/全局范围和类成员之间的歧义,则这样做的代价很小并且不会引入与 C++ 相关的概念差别。

更大的差别是缺少析构函数。这是所有垃圾回收语言共有的一个问题。就编程人员所知,对象析构并不具备确定性,因此必须以显式方式释放系统所拥有的资源。与 C++ 不同,您不能依赖析构函数“记住”在您之后进行清理。由于您很少拥有系统资源(甚至数据库连接也是在 HTTP 请求结束时释放的),因此这不是一个大问题。

PHP4 中的构造函数与 C++ 的析构函数基本相同,唯一的差别是不存在对基本类构造函数的自动嵌入调用。换言之,必须显式调用基本类构造函数。因此,在编写派生类时的第一件事就是在您忘记(以及在它开始为您带来麻烦之前)之前编写 $this->BaseClass(); 语句。

在我们抛开低级方面的问题(通常容易让人想起 C 而不是 C++)之前,先来了解一下 switch 参数。PHP 接受 switch 参数形式的字符串,而 C switch 只接受本地类型 — 整数或指针。一个相当不错的变化,确实很不错。

因此如果您比较仔细的话,是可以创建对象的

我对 PHP 了解的时间越长,就越能体会到,即使它在很多细节方面不同于 C++,但这两种语言之间并没有概念方面的差别,因此多年的 C++ 经验可以实现不错的实践。

必须注意的是,对象支持是 PHP 的事后补充(据说,它是由 Zeev Suraski 和 Andy Gutmans 在一个晚上增加出来的),因此它的实现并非万无一失,并会使您做出一些最终导致您失眠的事情。

另一方面,您在 C++ 方面受到的培训将帮助您避免对象 PHP 陷阱。C/C++ 已经使您学会像编译器那样进行思考,感觉在内存中一定正在执行某种操作,破解神秘的错误消息,猜测语言设计人员所做的折中 — 当然还要注意,PHP 实际上全部由 C 组成。

因此,可以肯定的是,您对 C++ 的理解越深,那么 PHP 和 C++ 的使用就越简单。

未知领域摸索

对象方法学对系统化的实践起到促进作用。PHP 的某些方面令人感到困惑,并且使其无法由对象进行处理。例如,在 PHP4 中,对象赋值 (operator =) 将对象复制到左侧值。该复制的狭窄深度始终不清楚,并通常与手头的问题无关。只需让系统利用引用即可避免此问题:

$objref=&$obj; 

除非您明确要克隆对象,否则复制通常会为您的程序带来设计缺陷,并在假定其表示同一数据片断时导致两个(或更多)对象处于或多或少的不一致状态。这将导致内存浪费频繁出现,并引起混淆。在 PHP5 中您可以避免这个问题!

这里,您的 C++ 背景将再次派上用场。复制构造函数这一烦恼一定已经教会您要使事情尽量简单。

我忘记了模板和函数指针。
后续步骤

论坛:Oracle 上的 PHP

PHP 漫游者指南

开放源代码开发人员中心

Oracle + PHP 疑难解答指南

PHP 脚本编制:随心所欲的代码逐渐流行

Oracle + PHP 使用入门

在 Linux 上安装 Oracle、PHP 和 Apache

我已经完全痴迷于泛型。将时间更多用于标识和解决各种问题,而不是反复编写同一代码片断。

尽管有时比较难以理解,但模板仍是 C++ 的一个优秀特性。当您意识到通过谨慎地使用模板可以从编译器中完成大量工作后,您将很有可能对其入迷。

因此,它使得采用一种缺乏泛型的语言失去了吸引力。

实际上,通过回调或代码生成在 PHP 中使用泛型非常容易。

对后者加以介绍将需要一整篇文章或一整部书籍。我们只是指出,可以使用 PHP/XML 技术轻松地实现它。

PHP 回调在概念上相当于 C 函数指针。无论对哪种语言而言,回调之于编程就相当于动词之于语言表达(当然,变量相当于名词)。书本示例是枚举:假设您想要列出一组订单。表示代码无法识别数据是来自平面文件、XML 还是 SQL 查询。它所要做的就是调用枚举程序,并向其传递回调来处理最终的调用:

/**
* Process one order independently of data source
*
* @param $order_data mixed Whatever data is
* @return boolean true if OK or false
*/
function print_order($order_data)
{
 // Process order data (output one record for instance)
 echo ('<tr><td>'.$order_data.'</td></tr>');
 return true;
}

/**
* Enumerates order records through callback
*
* @param $caller string Name of callback.
*/
function enum_orders($callback)
{
 while (/* whatever it takes to retrieve one order */)
 {
  // Here's one record, handling is up to caller.
  if (!call_user_func($callback,$order_data))
  {
   break;
  }
 }
}

// Now let's use it
<?php enum_orders('print_order'); ?>

现在,我们可能要通过邮件发送这些订单,而不仅仅是打印它们。我们只需更改回调,即:

<?php enum_orders('mail_order'); ?>

好了,该操作比较简单,我们可以做得更好(调用一个对象的方法)。重要之处在于,可以像在 C++ 中那样来使用回调(就设计而言,它们由字符串组成,而不是由指针组成)。

尽管回调很不错,但它们仍有些陈旧,它们类似于 SDK 并且不使用对象功能。我们采取进一步操作,将其重新分组为接口。

这需要抽象类。PHP 确实支持此特性:

// C++
class IMyInterface
{
public: 
 // Virtual methods declared with "=0" are abstract
 virtual void fun1(int  nParam) = 0;
 virtual void fun2(long lParam) = 0;
}

// PHP
class IMyInterface
{
 // Methods declared with "{}" are abstract
 function fun1($nParam) {}
 function fun2($lParam) {}
}

接口定义了一个您或其他人将通过实施抽象类来实现的“协定”。好处在于,实施将如同备件一样是可替换的软件组件。

当应用程序逻辑开始扩大(它最终是要扩大的)时,此编程样式将对不断增强的复杂性和对线性演化的持续控制具有重要意义。

下一个逻辑步骤是使用类工厂,但这将远远超出本文的范围。

现在,正如我所希望的,如果阅读这些代码行已经增强了您对对象 PHP 的兴趣,请访问 www.reflexivecms.org。其中的 XML/PHP 框架将具备更深入的功能。

快速比较研究

这些相似语言具备较强的相似性以及明显的差异性:

 C++PHP
Class MyClass :public BaseClass {} class Class MyClass extends BaseClass {}
继承多个简单
构造函数MyClass() {}function MyClass() {}
析构函数˜MyClass() {}
参数传递按值传递,但指针的大量使用使其等同于引用(引用受也支持)。默认情况下的按值传递对象使得 PHP 与众不同。PHP 5 将使其在使用方面与其他对象语言一样。
-> operator指向类或 struct 成员的指针。到类成员的访问(在许多语言中可能是“点 (dot)”,但点已经是字符串连接操作符)。PHP 中没有指针。
f()->g() 调用可随意嵌套。将受 PHP 5 支持。在此之前使用保存的返回值(一个分两步的过程)

$r=&f(); // step 1
$r->g(); // step 2
类型系统静态类型。动态类型。
字符串不是本地类型 (ASCIIZ)。本地支持。
数组静态动态 — 关联
垃圾收集器无,; 管理内存manage memory the hard way.所有系统资源都可进行垃圾收集。
预处理程序非常详细。没有 define() 支持。
语言级别L3G(带有类似于 L4G 的库)L4G,有时与 L3G 非常相似。

总结

经过一年半的 PHP 涉猎之后,我发现在使用该语言时,网络编程与计算机编程的差别并不明显。只需略加留意即可轻松地转变编程实践,并且使用现代化的对象方法并不存在自身限制或性能损失。

熟练使用 C++ 可以防止您对 PHP 采用简单的方法,以免在事情复杂化时使您遇到麻烦。它还可以帮助您了解 PHP5 和更高版本的发展方向。

熟悉 PHP 值得您花时间。


Philippe Lachaise (plachaise@virtualmice.net) 从 80 年代中期的大型机环境中开始涉足 IT 业。在转移到计算机软件的专业转换领域后,他开始认真编程,以创建提升转换效率的工具。他是对象技术的早期使用者,因而具有各种对象应用程序开发经验。

现在,Lachaise 正在学习和使用 Web 标准。为了使历史悠久的对象开发实践与 Web 约束协调,他最近一直在开发 RefleXiveCMS,一个旨在根据十多年的 C++ 和组件经验转换为 Web 开发的 XML/PHP 应用程序框架。

 

请为本文评定等级:

优秀 良好 一般 低于一般水平 较差


将您的意见发送给我们

E-mail this page
Printer View Printer View