Archive for 八月, 2005

[转]各种License规范的异同

八月 30th, 2005 by xLight

今天做一项工作的时候,由于想利用网上现有的class LIB,所以查找了一些关于协议的文章,

这里是一篇 分析的还不错的,与大家共享

本篇文章属于》IT文摘 , LINUX

以下引用 :) 【From Wikibooks, the free textbook project】

各种开源软件授权方式的选择

各种开源软件授权方式的介绍
首先介绍开源软件的共同的特点:源代码开放、免费修改、免费重新发布。

  以BDS为代表的接近于公共域软件的授权。包括Xwindows、freeBDS、apache、perl、python、ruby、zope等。其中apache的授权叫APL,是一种比较典型的授权声明,下面对于近似公共域的授权以APL表示。这种授权的特点就是虽然保留版权,但不但免费修改、免费重新发布,而且允许商业使用,允许商业修改后不公布修改的软件代码。是对商业软件友好的授权方式。

  以GPL为代表的自由软件,包括linux、gcc、KDE、gnome等。允许免费修改、免费重发布,但要求修改代码必须也遵守GPL。这种授权方式大大限制了从开源中牟利的手段,因此是对商业不友好的授权,对商业不友好的后果是不能使开源代码产生更广泛的效果、不能调动商业软件开发力量。但也要看到GPL对打破垄断的价值,打破垄断对所有的商业软件也是有利的。在GPL下面还有一种对商业更友好的方式就是LGPL,允许商业代码链接LGPL代码,这样商业软件在利用LGPL软件的同时能够很大程度上保留商业利益。gnome是LGPL的(不确定),KDE是GPL的。因此在KDE上面实现商业软件比较困难,因此说KDE是开放不充分的。

  以MPL为代表的商业公司的开源策略。包括mozilla、openoffice等。允许免费重发布、免费修改,但要求修改后的代码版权归软件的发起者,这样发起者和组织者具有更优越的地位。MPL一般也是同时遵守LGPL的。这是因为GPL比较严格,不会产生另一个商业的竞争者。MPL也是对商业友好的。并且用一些优惠来鼓励商业软件开源。

  关于GPL,如果开源软件的开发要借助社区的力量,那么最好是用GPL授权,因为这样可以防止商业软件抢走用户而导致的开源软件的使用者和开发者都不足。

  如果开源软件的开发部需要借助社区的力量,而是封闭开发,使用BSD授权是最恰当的授权。因为既然不需要借助社区的力量,用户的多少和后加入开发的人的多少都没有关系,并且同样可以达到开源软件给用户修改和重新发布的自由。并且:一、如果允许修改者商业化,则更加调动了修改者的积极性,可以弥补开源软件不注重豪华功能的缺陷,使小部分用户的特殊需要也能够得到满足,和开源软件形成互补关系。如activepython就是对python的很好的补充。二、开源软件的使用范围也更广,对社会的贡献也更大。比如现在python被引入到.net支持的语言范围内,而如果python是GPL,则这种情况是不可能发生的。三、比如nextstep,beOS,macX的出现说明BSD使商业软件的起步更高,促进了商业软件的发展,对用户来说获益更大。(我认为开源和商业并不矛盾,而是相互补充,用户都需要)。四、不但对用户有好处,也对软件发展的基石–开发人员有好处。使开源软件的开发者在促进开源的同时还可以使自己的事业得益于开源代码,避免了学习投入的浪费,也使开发的重复工作量最小。(使软件开发在更庞大的基础上继续前进会节省大量的社会资源,会使软件的开发成果更快发展,会出现更多精彩的软件,而每个公司都从基础做起是对社会的更大浪费,这个问题需要政府和更多的公益事业人员意识到,软件这种不同于其他产品的可继承性的特点需要大家注意,如果立法能够把商业软件的著作权保护期缩短,并且强制开源,和专利的情况接近,那么对社会进步的好处会更大,除了对公司垄断获得超额利润有影响外,对正常获利也没有影响)

  当然,选择GPL或BSD授权还和人的价值观有关系,但以开发类型来选择授权方式是比较合理的。如果采用封闭开发,使用BSD也可以达到GPL的效果,而采用社区开发,BSD会对开发团队的成长不利。如果在没有商业化价值的领域,GPL完全没有必要。

  MPL授权是商业软件想要借助社区的力量的产物。

  LGPL对有商业化的友好性和GPL相比是大大提高了,在很多情况下对商业化都没有阻碍,可以说达到了50%的商业化的要求,但有时商业化需要对源代码的彻底修改,因此不能说LGPL百分之百满足商业化要求,LGPL是一个折衷的授权,如果社区开发的软件希望能在更大的范围内被使用,可以采用LGPL。

  各种软件授权的优缺点及适用范围和变种(增订版)

  APL的优点:能够同时和GPL和商业授权相兼容,使APL的软件代码得到最大限度的利用。
APL的适用范围:如果软件要求有更广泛的使用范围,为了成为行业标准,或在使用中只有做修改才能应用,为了不失去商业客户,只能选择APL。
APL的缺点:没有竞争力,用户容易被在APL基础上开发的GPL和商业软件抢走用户。失去用户的结果就是失去社区开发者,因此,APL软件不适合社区开发。
APL的变种:BSD license、ZPL、artist license和APL的条款类似。而变种公共域软件则没有任何要求,包括保留作者名称的要求,标出修改内容的要求和改变软件名程的要求。
APL和公共域类软件有apache、perl、python、ruby、zope、xwindows、tex、freeBSD

  GPL的优点:开放源代码,能够保证开发成果不被商业的竞争对手掠夺,能保证用户的忠诚和稳定的社区开发者来源。
  GPL的缺点:不能商业使用,限制了代码的应用范围,因此,不能获得商业开发对用户的好处。如果软件的用户范围小或软件某些功能的用户范围小、开发量大,就不能保证社区开发者的数量,也就不能获得持续的开发。GPL虽然可以应邀开发某些功能,但不如商业软件经济,因为商业软件可以向多个用户收费。
GPL的适用范围:GPL软件生存的前提是用户数量要大,特殊的开发要求要少,适合通用软件。
GPL的变种:MPL要求所有的修改都将版权无偿归软件的创始人所有,而创始人能决定代码的商业使用或改变授权形式。MPL软件无偿使用。
  GPL软件还有一种重要的变种,就是对个人使用免费,对商业使用付费。其中很多是以GPL的方式出现的,因为GPL不允许链接,象各种库就被禁止商业使用了,这些库如果没有采用LGPL授权,那么它们就自然禁止免费商业使用。比如cygwin、berkleyDB、KDE。还有一些开源软件明确说明禁止商业使用。
GPL软件有gcc、linux、glibc、gnome、open office等。

  非LGPL软件,对商业使用付费的软件有cygwin、berkleyDB、KDE、ghostscript的高版本。
  MPL软件有mozilla、sun的java编译器、vim

HTTP 1.1状态代码及其含义

八月 25th, 2005 by admin

下表显示了常见的HTTP 1.1状态代码以及它们对应的状态信息和含义。

转载请注明来源:文章大全 网址:http://www.itlearner.com/article/

   应当谨慎地使用那些只有HTTP 1.1支持的状态代码,因为许多浏览器还只能够支持HTTP 1.0。如果你使用了HTTP 1.1特有的状态代码,最好能够检查一下请求的HTTP版本号。

状态代码 状态信息 含义
100 Continue 初始的请求已经接受,客户应当继续发送请求的其余部分。(HTTP 1.1新)
101 Switching Protocols 服务器将遵从客户的请求转换到另外一种协议(HTTP 1.1新)
200 OK 一切正常,对GET和POST请求的应答文档跟在后面。
201 Created 服务器已经创建了文档,Location头给出了它的URL。
202 Accepted 已经接受请求,但处理尚未完成。
203 Non-Authoritative Information 文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝(HTTP 1.1新)。
204 No Content 没有新文档,浏览器应该继续显示原来的文档。如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的。
205 Reset Content 没有新的内容,但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容(HTTP 1.1新)。
206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它(HTTP 1.1新)。
300 Multiple Choices 客户请求的文档可以在多个位置找到,这些位置已经在返回的文档内列出。如果服务器要提出优先选择,则应该在Location应答头指明。
301 Moved Permanently 客户请求的文档在其他地方,新的URL在Location头中给出,浏览器应该自动地访问新的URL。
302 Found 类似于301,但新的URL应该被视为临时性的替代,而不是永久性的。注意,在HTTP1.0中对应的状态信息是“Moved Temporatily”。

出现该状态代码时,浏览器能够自动访问新的URL,因此它是一个很有用的状态代码。

注意这个状态代码有时候可以和301替换使用。例如,如果浏览器错误地请求http://host/~user(缺少了后面的斜杠),有的服务器返回301,有的则返回302。

严格地说,我们只能假定只有当原来的请求是GET时浏览器才会自动重定向。请参见307。

303 See Other 类似于301/302,不同之处在于,如果原来的请求是POST,Location头指定的重定向目标文档应该通过GET提取(HTTP 1.1新)。
304 Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。
305 Use Proxy 客户请求的文档应该通过Location头所指明的代理服务器提取(HTTP 1.1新)。
307 Temporary Redirect 和302(Found)相同。许多浏览器会错误地响应302应答进行重定向,即使原来的请求是POST,即使它实际上只能在POST请求的应答是303时才能重定向。由于这个原因,HTTP 1.1新增了307,以便更加清除地区分几个状态代码:当出现303应答时,浏览器可以跟随重定向的GET和POST请求;如果是307应答,则浏览器只能跟随对GET请求的重定向。(HTTP 1.1新)
400 Bad Request 请求出现语法错误。
401 Unauthorized 客户试图未经授权访问受密码保护的页面。应答中会包含一个WWW-Authenticate头,浏览器据此显示用户名字/密码对话框,然后在填写合适的Authorization头后再次发出请求。
403 Forbidden 资源不可用。服务器理解客户的请求,但拒绝处理它。通常由于服务器上文件或目录的权限设置导致。
404 Not Found 无法找到指定位置的资源。这也是一个常用的应答。
405 Method Not Allowed 请求方法(GET、POST、HEAD、DELETE、PUT、TRACE等)对指定的资源不适用。(HTTP 1.1新)
406 Not Acceptable 指定的资源已经找到,但它的MIME类型和客户在Accpet头中所指定的不兼容(HTTP 1.1新)。
407 Proxy Authentication Required 类似于401,表示客户必须先经过代理服务器的授权。(HTTP 1.1新)
408 Request Timeout 在服务器许可的等待时间内,客户一直没有发出任何请求。客户可以在以后重复同一请求。(HTTP 1.1新)
409 Conflict 通常和PUT请求有关。由于请求和资源的当前状态相冲突,因此请求不能成功。(HTTP 1.1新)
410 Gone 所请求的文档已经不再可用,而且服务器不知道应该重定向到哪一个地址。它和404的不同在于,返回407表示文档永久地离开了指定的位置,而404表示由于未知的原因文档不可用。(HTTP 1.1新)
411 Length Required 服务器不能处理请求,除非客户发送一个Content-Length头。(HTTP 1.1新)
412 Precondition Failed 请求头中指定的一些前提条件失败(HTTP 1.1新)。
413 Request Entity Too Large 目标文档的大小超过服务器当前愿意处理的大小。如果服务器认为自己能够稍后再处理该请求,则应该提供一个Retry-After头(HTTP 1.1新)。
414 Request URI Too Long URI太长(HTTP 1.1新)。
416 Requested Range Not Satisfiable 服务器不能满足客户在请求中指定的Range头。(HTTP 1.1新)
500 Internal Server Error 服务器遇到了意料不到的情况,不能完成客户的请求。
501 Not Implemented 服务器不支持实现请求所需要的功能。例如,客户发出了一个服务器不支持的PUT请求。
502 Bad Gateway 服务器作为网关或者代理时,为了完成请求访问下一个服务器,但该服务器返回了非法的应答。
503 Service Unavailable 服务器由于维护或者负载过重未能应答。例如,Servlet可能在数据库连接池已满的情况下返回503。服务器返回503时可以提供一个Retry-After头。
504 Gateway Timeout 由作为代理或网关的服务器使用,表示不能及时地从远程服务器获得应答。(HTTP 1.1新)
505 HTTP Version Not Supported 服务器不支持请求中所指明的HTTP版本。(HTTP 1.1新)

将EXCEL文件导入MySQL

八月 22nd, 2005 by admin

1. 首先将 eXCEL 文件保存为CSV格式。本例中我将文件保存为“c:/book.csv”。
2. 按照CSV文件的结构,在Mysql 创建TABLE。
3. 执行如下SQL命令:
LOAD DATA LOCAL INFILE 'c:/book.csv'
    INTO TABLE book
    FIELDS
        TERMINATED BY ','
    LINES TERMINATED BY 'rn'
后记:你也可以在sql命令中设定 导入的字段,详细的去看manual吧!
update 08-23-2005:  1. 修正被blog程序自动过滤掉的“”,使用“\”显示(注意换成半角字符),    可以躲过输入过滤;但再次编辑此文件时发现所有的“\”都被替换为了。    还没有研究这是为什么;  2. 修正一个错别字。

今天收到了一封令我感到很意外的mail

八月 12th, 2005 by xLight

from:(某超级资深网络名人)
title:对您的简历很感兴趣~ 呵呵,想不到会收到他的来信,在我眼里它绝对可以算是传奇人物了,个性十足,略有偏执。

由于我刚刚安定下来,刚刚基本适应新的工作环境和生活环境,暂时不想重返北京,所以只好回绝了他。

:( 怎么我经常回绝好工作呢?唉!

刚才又一个同事要离职了,据说要跳到 通用 去了,听到这个消息还真有点后悔上边的决定呢,呵呵

决定了,就没有后悔这条路


google搜索的技巧

八月 9th, 2005 by xLight

关于搜索引擎的一个好网站:http://www.se-express.com/

1. 搜索flash文件:filetype:swf

2. 在sina网范围内搜索:site:sina.com.cn

3. url中包含midi:inurl:midi ,针对url搜索: allinurl:”cgi-bin” phf +com

4. “intitle”和“allintitle”的用法类似于上面的inurl和allinurl。网页设计的一个原则就是要把主页的关键内容用简洁的语言表示在网页标题中。因此,只查询标题栏,通常也可以找到高相关率的专题页面。

示例:查找日本明星藤原纪香的照片集。
搜索:“intitle:藤原纪香 “写真集””

5. 如果你拥有一个个人网站,估计很想知道有多少人对你的网站作了链接。而“link”语法就能让你迅速达到这个目的。

示例:搜索所有含指向华军软件园“www.newhua.com”链接的网页。
搜索:“link:www.newhua.com”

习题:搜索chinaren中咱们班有关“猪头”的信息。你的答案呢?:D

再推荐3个google页面:

http://www.google.com/apis/

http://labs.google.com/

http://www.google.com/press/zeitgeist.html (记得点击Zeitgeist Around the World) 很有趣,看看中国人都在使用google搜索什么?

用 PHP 开发健壮的代码(二):有效地使用变量

八月 2nd, 2005 by admin

作者:Amol Hatwar    文章来源:IBM中国    

用 PHP 开发健壮的代码”是关于解决大中型应用程序中的实际问题的系列文章。在本文中,PHP 老手 Amol Hatwar 讨论了如何有效地使用变量。他还演示了如何通过使用 PHP 中可变的变量名来构造配置文件解析器,以便简化脚本配置

用 PHP 开发健壮的代码(二):有效地使用变量
作者:Amol Hatwar    文章来源:IBM中国    点击数: 187    更新时间:2004-3-20
用 PHP 开发健壮的代码”是关于解决大中型应用程序中的实际问题的系列文章。在本文中,PHP 老手 Amol Hatwar 讨论了如何有效地使用变量。他还演示了如何通过使用 PHP 中可变的变量名来构造配置文件解析器,以便简化脚本配置。

在我的前一篇文章中,我研究了在规划、设计甚至编写代码期间必须考虑的一些因素。在本文中,您将真正接触到实际代码,并可以看到实际运行中的一些东西。如果您还没有看过前一篇文章,那么最好现在就看一看。

正确处理变量
变量与函数是任何计算机语言必不可少的要素。有了变量,您可以将数据抽象化;有了函数,您可以将几行代码抽象化。正如 Bruce Eckel 在他的书籍《C++ 编程思想》中所说的那样,所有编程语言都提供抽象。汇编语言是对底层机器的小抽象。随后的许多所谓的命令式语言(如 Fortran、BASIC 和 C)是对汇编语言的抽象。

编程语言提供的抽象的种类和质量直接关系到您所能解决的问题的复杂程度。理解 PHP 如何处理变量和函数,将有助于您有效地使用它们。

名称里有什么?
就象我在前一篇文章中提到的那样,命名约定和编码约定是重要的。无论您使用什么命名约定,请记住要在项目中严格遵守它。如果您使用应用得最广泛的命名约定,那么您的代码将被更多的人所接受。

对变量进行命名时,在包括脚本时要特别注意不要覆盖正在使用的变量。在大型应用程序中,当增加新的功能时,这是常见的错误根源。防止这一问题的最佳办法就是使用前缀。把变量所在模块的名称缩写作为前缀来使用。例如,如果一个处理投票的模块中有一个保存用户标识的变量,那么您可以将该变量命名为 $poll_userID$pollUserID

理解 PHP 变量
PHP 是解释型语言。这有许多好处,很快您将学习利用其中的一些。第一个很明显的好处是:它使您省掉了设计-编码-编译-测试周期 — 您在编辑器中编写的任何代码都立即可使用。然而,最重要的好处是您不用担心变量的类型以及如何在内存中管理这些变量。所有分配给脚本的内存在执行完脚本后都由 PHP 自动收回。此外,可以对变量执行许多操作而不必知道变量的类型。清单 1 中的代码在 PHP 中工作十分正常,但在 C 和 Java 语言中会抛出一大堆错误消息:

清单 1. 带变量的样本 PHP 代码


<?php
$myStr = 789696;                       // An integer.
$myVar = 2;                            // Another integer.
$myStr = "This is my favorite band: "; // Strings are more fun.
$myStr = $myStr . "U" . $myVar;        // Doing this is OK, too.
echo "$myVarn";
?>

安装完 PHP 后,如要运行运行代码,可首先将该代码保存为一个 .php 文件,再将该文件放置在 Web 服务器上,然后将浏览器指向该文件。更好的办法是安装 PHP 的 CGI 版本。然后,通过在 shell 或命令提示符下输入以下命令,并用包含您的脚本的文件名替代 script-name,这样就可以运行该脚本了。

path-to-php/php script-name

该代码能够正常工作,因为 PHP 是类型宽松的语言。用通俗易懂的英语,可以不考虑变量类型,可以把字符串赋值给整数,以及毫不费力地用较大的字符串替代较小的字符串。这在象 C 这样的语言中是不可能的事情。在内部,PHP 将变量所拥有的数据与类型分开存储。类型存储在单独的表中。每当出现包含不同类型的表达式时,PHP 自动确定程序员想要做什么,接着更改表中的类型,然后自动对表达式求值。

介绍一个常见的小问题
不用担心类型固然很好,但有时那也会使您陷入真正的麻烦。怎么回事呢?这里有一个实际的示例:我常常必须把在基于 Windows 的 PC 上创建的内容移到 Linux 系统,以便能在 Web 上使用它们。基于 Windows 的文件系统在处理文件名时是不区分大小写的。文件名 DefParser.php 和 defparser.php 指向 Windows 上的同一文件。在 Linux 操作系统上,它们指向不同的文件。您可能提倡文件名要么全用大写,要么全用小写,但最好的做法应该是使大小写保持不变。

解决这个小问题
假设您想要一个函数,它能在不考虑大小写的情况下检查给定文件是否存在于某个目录中。首先,将这个任务分解成一些简单的步骤。分解代码可能听起来有些可笑,但它确实有助于您在编写代码时将主要精力放在这段代码上。另外,在纸上重写步骤始终比重写代码容易得多:

  1. 获取源目录中的所有文件名
  2. 过滤掉 . 和 .. 目录
  3. 检查目标文件是否存在于该目录中
  4. 如果文件存在,则获取具有正确大小写的文件名
  5. 如果名称不匹配,则返回 false

要读取目录的内容,需要使用 readdir() 函数。可以在 PHP 手册(请参阅参考资料)中获取有关该函数的更多细节。至于现在,只要知道:readdir() 在每次调用时会逐个返回给定目录中所有文件的名称。在列出了所有的文件名后,它返回 false。您将使用一个循环,该循环在 readdir() 返回 false 时终止。

但这样就够了吗?请记住,PHP 是类型宽松的语言,这意味着会将整型值 0 与 false 视为相同(甚至 C 也把 0 和布尔值 false 视为等价)。问题不是该代码是否能正常工作;想象一下,如果文件的名称是 0 会如何!该脚本会过早终止。可以使用以下脚本(清单 2)来确定 0 与布尔值 false 的等价性:

清单 2. 确定 0 与布尔值 false 是否等价的脚本


<?php
$file_name = 0;
if (0 == $file_name ) {
echo "The code is in trouble ...n";  // This text prints on the screen.
}

else {
echo "Phew ... The code is safe";   // This text never prints.
}
?>

那么您可以做什么呢?您知道 PHP 会在内部存储类型,而如果能够访问这些类型的话,问题就解决了。布尔值 false 和整型值 0 明显是不同的。

PHP 有一个 gettype() 函数,但让我们在这里选择更简单的方法。您可以使用 === 运算符(是的,有三个等号)。不同之处在于该运算符同时比较数据的值和类型。如果您对此觉得有些疑惑,PHP 还有 !== 运算符。只有 PHP 4 中才有这些新型运算符和 gettype() 函数。清单 3 显示了解决该问题的完整代码:

清单 3. 完整代码


<?php
/* This is the function where the action takes place */
function chk_file_name( $name, $path="." ) {
	$fileList = get_file_list($path);
	foreach ($fileList as $file) {
		if (eregi($name, $file)) {
			return $file;
		}
	}
return false;
}

/* Return the list of files in a given directory in an array.
    Uses the current directory as default. */
function get_file_list($dirName=".") {
	$list = array();
	$handle = opendir($dirName);
	while (false !== ($file = readdir($handle))) {

	/* Omit the '.' and the '..' directories. */
		if ((".."== $file) || ("."== $file)) continue;
		array_push($list, $file);
	}

	closedir($handle);
	return $list;
}

?>

观察中得到的经验
我不打算对清单 3 中各个函数的功能加以说明,相反,我鼓励您查阅 PHP 手册(请参阅参考资料)。当您使用不熟悉的函数时,假设的参数与返回值的类型会是另一个错误根源。我没有对 PHP 中的内置函数加以说明,而是打算说明一些不太一目了然的事情。

当终止条件中涉及不同的变量类型时,通过使用 ===!== 运算符进行强类型检查是很重要的。

由各部分组成的代码
我本来可以将整个脚本编写为一个函数,但这里我却把代码分割成两个函数。还记得前一篇文章中的“分而治之”规则吗?我这么做正是因为每个函数所起的作用不同。如果您用其它脚本获取某个目录的内容,那么现在就可以使用方便的实现。我希望您考虑一些事情:想象一下将整个脚本作为一个函数来实现,然后想象调试、测试和重用代码所需的工作。

正确使用循环
现在看看 foreach 循环,想想为什么不用 for 循环?使用 for 循环要求您知道数组中项的数目 — 需要一个额外的步骤。此外,在处理 PHP 数组时,有可能超出数组边界。也就是说,在数组只有 10 个元素时,试图访问它的第 15 个元素。PHP 的确会给出一个小警告,但据我所知,在一些情况下,当反复运行某个脚本时,CPU 活动率会突然上升到 100% 而服务器性能则连续下降。我建议您尽可能地避免使用 for 循环。

断言性的 if
最后,我希望您研究一下那个在 get_file_list() 函数中用于忽略 . 和 .. 目录的较大的 if 条件。显然,我可以采用传统的方法,根据常数来检查变量。但在我自己的许多编码昏招中,我经常会遗漏等号并且在以后找不到哪里出了问题。当然,PHP 不会报错,因为它认为我想进行赋值而不是比较。当您根据变量来比较常数并且又遗漏了一个等号时,PHP 会抛出错误消息。

可变的变量名
现在来讨论一些奇妙的事情。作为新手的开发人员认为,使用可变变量来完成任务是一种令人费解的方法,所以常常回避它。实际上,很容易理解和使用可变变量。它们已经不止一次地帮我摆脱困境,而且它们是一种重要的语言元素。事实上,在有些情况下,使用可变变量在所难免。很快我将研究一种此类现实情况,但首先让我们看看可变变量到底是什么。让我们先尝试一下清单 4 中的代码:

清单 4. 具有可变变量的代码


<?php
$myStr = "I";
$$myStr  = "am";
$$$myStr = "great.";

// These are new variables.
echo "$myStr ";
echo "$I ";
echo "$amn";

// Now for the moment of truth ...";

$am = "exaggerating.";

// Does it work the other way?
echo "$myStr ";
echo "${$myStr} ";
echo "${${$myStr}}n ";
?>

首先,清单 4 中的代码声明了名为 $myStr 的变量,并将字符串 I 赋给它。接下来的语句定义了另一个变量。但这次,变量的名称是 $myStr 中的数据。$$myStr 是一种告诉 PHP 产生另一个变量的方法,其意思是“我想要一个变量,可以在变量 $myStr 中找到这个变量的名称”。当然,为做到这一点,必须定义 $myStr。所以,现在您有一个名为 I 的变量,并用字符串 am 给它赋值。接下来的语句做了同样的事情,并将字符串 great 赋给名为 am 的变量。而 am 只是变量 I 中的数据。

那澄清了一些事,但 echo 语句中那些奇怪的花括号是怎么回事呢?那就是您打印可变变量的方法。如果您省略花括号,那么 PHP 在打印时会将美元符号($)附加到变量的内容上。这些花括号告诉 PHP 首先对它们里面的变量求值。

试着这样考虑:变量可以做什么?简单地说,它们抽象或表示数据,这些数据可以变化,而它们的名称保持不变。可变变量做的是同样的事情;它们抽象数据。但在本例中,它们包含的数据实际上是另一个变量的名称。

我在清单 4 中所给的例子是为了让您熟悉可变变量。可变变量名的实际功能来自这样的事实:您可以在运行时动态地生成可变的变量名。您将在构造一个配置文件解析器时用到这一特性。

配置文件解析器
按照我的经验,在配置应用程序以使其运行期间,用 PHP 编辑配置文件时,用户常有所抱怨。配置只不过是全局变量的一个列表,应用程序中的其它脚本依靠它来查找文件、URL 和其它控制应用程序行为的设置。一个遗漏的美元符号、分号或一段未封闭的注释常常会破坏整个代码。有什么能帮助用户呢?

假设您给用户一个文件,让用户使用由等号分开的简单的名称-值对来编辑该文件。配置文件类似于清单 5。以 # 开头的行的文本被作为注释处理。

清单 5. 样本配置文件


# This is sample a configuration file.
admin_fname = Amol
admin_lname = Hatwar
admin_email = amolhatwar@consultant.com
admin_login = admin
admin_pass = secretstring
# File Ends

意思清楚吗?是的,的确如此……既然可以用 PHP 解析文件,为什么让用户编辑配置文件呢?事实上,这是人们非常期望的。请记住,您的应用程序必须在对用户隐藏所有复杂性的同时,仍然让他知道他能控制该应用程序。

您可以编写负责解析工作的函数,这样您可以在任何地方使用它而不用做任何修改。让我们将该任务分为一些更简单的步骤:

  1. 逐行地读取文件
  2. 丢弃一行中 # 号字符后的所有内容
  3. 以等号为界,将一行分为两个字符串,并丢弃等号
  4. 除去字符串中的额外空格
  5. 相应声明变量

要编写最后一步,只有使用可变变量才行。清单 6 显示了代码:

清单 6. 解析函数


<?php
/* conf_parser.php */

/* Give the filename with path info whenever possible. */
function conf_parse($file_name) {

// @ in front makes the function quiet. Error messages are not printed.
$fp = @fopen($file_name, "r") or die("Cannot open $file_name");

while ($conf_line = @fgets($fp, 1024)) {
$line = ereg_replace("#.*$", "", $line);   // Do stripping after hashes.
if ($line == "") continue;   // Drop blank lines resulting from the previous step.
list($name, $value) = explode ('=', $line);   // Drop '=' and split.
$name = trim($name);   //  Strip spaces.
$$name= trim($value);   // Define the said variable.
}
fclose($fp) or die("Can't close file $file_name");
}
?>

用正则表达式除去 # 号。尽管这里的表达式很简单,但要知道复杂的正则表达式会消耗大量的 CPU 时间。此外,为每页反复地解析配置文件不是一个好的决策。更好的选择是:使用变量或定义语句将已解析的输出存储为 PHP 脚本。我倾向于使用 define() 函数进行定义,因为一旦设置了值就不能在运行时更改它。可以在参考资料中找到一个能够根据您的需要加以修改的实现。

结束语
既然知道了如何有效地使用变量,那么您可以着手编写一些较大的程序了。在本系列的下一篇文章中,我将研究函数和 API 设计。在下次见面以前,希望您编程愉快!

参考资料

  • 下载 def_parser.zip 文件,其中包含配置文件解析器的实现,您可以将该解析器写的文件包括在您的脚本中。

  • 请访问 PHPBuilder.com 和 Developer Shed,以获取更多有关在 PHP 中使用可变变量名称的示例。
  • 请阅读了解 Free Energy,这是一个对 Web 应用程序进行编码的简单方法。
  • 下载或在线查阅 PHP 手册
  • 参加“Writing efficient PHP”教程,学习如何编写有效的 PHP 代码(developerWorks,2002 年 7 月)。
  • 请阅读本系列文章中的第一篇“奠定基础”,了解有关设计和规划 Web 应用程序的要点(developerWorks,2002 年 8 月)。

关于作者
Amol Hatwar 从能记事起就开始接触计算机。作为 GNU/Linux 的绝对拥护者,他为过去在 Microsoft 平台上编程感到内疚。他现在作为独立顾问帮助众多公司迁移到 GNU/Linux。作为开发 Web 应用程序领域的专家,他把所剩无几的空余时间花在研究没人听说过的技术上。他现在的兴趣包括开放源码软件、Web 服务、对等计算以及高可用性群集。您可以通过 amolhatwar@consultant.com 与 Amol 联系。