PHP面向对象快速入门-----转

面向对象编程(OOP)是我们编程的一项基本技能,PHP4对OOP提供了良好的支持。如何使用 OOP的思想来进行PHP的高级编程,对于提高PHP编程能力和规划好Web开发构架都是非常有意义的。下面我们就通过实例来说明使用PHP的OOP进行编程的实际意义和应用方法。

  我们通常在做一个有数据库后台的网站的时候,都会考虑到程序需要适用于不同的应用环境。和其他编程语言有所不同的是,在PHP中,操作数据库的是一系列的具体功能函数(如果你不使用ODBC接口的话)。这样做虽然效率很高,但是封装却不够。如果有一个统一的数据库接口,那么我们就可以不对程序做任何修改而适用于多种数据库,从而使程序的移植性和跨平台能力都大大提高。

  在PHP中要完成OOP,需要进行对象封装,也就是编写类。我们可以通过生成一个新的SQL类实现对数据库的简单封装。例如:

< ?
class SQL
{
var $Driver; //实际操作的数据库驱动子类
var $connection; //共用的数据库连接变量
function DriverRegister($d)
{
if($d!="")
{
$include_path = ini_get("include_path");
$DriverFile = $include_path."/".$d.".php";
//驱动的存放路径必须在PHP.ini文件中设定的INCLUDE_PATH下
if( file_exists( $DriverFile)) //查找驱动是否存在
{
include($DriverFile);
$this->;Driver = new $d();
// 根据驱动名称生成相应的数据库驱动类
return true;
}
}
return false; //注册驱动失败
}
function Connect($host,$user,$passwd,$database)//连接数据库的函数
{
$this->;Driver->;host=$host;
$this->;Driver->;user=$user;
$this->;Driver->;passwd=$pas
swd;
$this->;Driver->;database=$d
atabase;
$this->;connection = $this->;Driver->;Connect();
}
function Close()//关闭数据库函数
{
$this->;Driver->;close($this->;connection);
}
function Query($queryStr)//数据库字符串查询函数
{
return $this->;Driver->;query($queryStr,$this->;connection);
}
function getRows($res)//查找行
{
return $this->;Driver->;getRows($res);
}
function getRowsNum($res)//取得行号
{
return $this->;Driver->; getRowsNum ($res);
}
}
? >;
  我们以操作MySQL数据库为例。我们写一个数据库驱动类MySQL,在该类中,我们把有关MySQL数据库操作的函数都做进一步的封装。把包含该类,文件名为MySQL.php的文件放在PHP的系统 include_path下,就可以正常地使用了。注意编写数据库驱动文件时,文件名应和类名保持一致。

< ?
Class MySQL
{
var $host;
var $user;
var $passwd;
var $database;
function MySQL() //利用构造函数实现变量初始化
{
$host = "";
$user = "";
$passwd = "";
$database = "";
}
function Connect()
{
$conn = MySQL_connect($this->;host, $this->;user,$this->;passwd) or
die("Could not connect to $this->;host");
MySQL_select_db($this->;database,$conn) or
die("Could not switch to database $this->;database;");
return $conn;
}
function Close($conn)
{
MySQL_close($conn);
}

function Query($queryStr, $conn)
{
$res =MySQL_query($queryStr, $conn) or
die("Could not query database");
return $res;
}
function getRows($res)
{
$rowno = 0;
$rowno = MySQL_num_rows($res);
if($rowno>;0)
{
for($row=0;$row<$rowno;$row++)
{
$rows[$row]=MySQL_fetch_row($res);
}
return $rows;
}
}
function getRowsNum($res)
{
$rowno = 0;
$rowno = mysql_num_rows($res);
return $rowno;
}
}
? >;
  同样我们要封装其他的“数据库驱动”到我们的SQL类中,只需要建立相应的类,并以同名命名驱动文件,放到PHP的include目录就可以了。

  完成封装以后,就可以在PHP中按照OOP的思想来实现对数据库的编程了。

< ?
Include(“SQL.php”);
$sql = new SQL; //生成新的Sql对象
if($sql->; DriverRegister(“MySQL”)) //注册数据库驱动
{
$sql->;Connect(“localhost”,”root”,””,”test”);
$res=$sql->;query(“select * from test”); //返回查询记录集
$rowsnum = $sql->;getRowsNum($res);
if($rowsnum >; 0)
{
$rows = $sql->;getRows($res);
foreach($rows as $row) //循环取出记录集内容
{
foreach($row as $field){
print $field;}
}
}
$sql->;Close();
}
? >;

  在实际应用中,我们还可以根据实际需求对各种对象类做进一步扩展。在PHP中,还提供了一系列复杂的OOP方法,例如继承,重载,引用,串行化等等。充分调动各种方法并灵活运用,就能够使你的网站更合理和结构化,开发和维护也更容易。PHP编程风格


在很多情况下PHP最可贵的特点也可能是它最薄弱的环节就是它的语法松散性。 PHP能够如此广泛的被使用,因为它使得许多没有经验的Web开发者能够制作出强大的应用程序,而用不着过多的考虑规划、连贯性和文档。
不幸的是,正是以上的特点,是的很多的PHP源代码很臃肿,很难阅读甚至无法维护。我深深的体会到这一点,因为我已经写了很多这样的代码。;-)
为了避免上面的情况以及很多其他的情况发生。很多的核心PHP开发人员和团体成员走到了一起,开始了PEAR,一个着力于增加PHP扩展和插件仓库的项目。到现在未知,来源于PEAR项目的文档和其他的东西还很少并且难以理解,这篇文章试图向开发者们讲述他们(PEAR小组)所做的事情。
决定代码可维护性的重要因素是代码的格式和注释。一个工程的所有代码应该以贯穿始终的形式组织。我非常坚持代码库的建设,我想程序员们也应如此。
(1)缩进
开发者所有的代码应该完全按照缩进的方式书写。这是提高代码可读性最基本的措施。即使你没有注释你的代码,缩进对于让其他人读懂
你的代码也是非常大的帮助。
例如下面的例子:
while ($x < $z) {
if ($a == 1) {
echo A was equal to 1;
} else {
if ($b == 2) {
//do something
} else {
//do something else
}
}
}
PEAR 草案标准要求利用4个空格缩进而不是利用tab。我个人并不同意这个观点,我想我仍然会继续利用tab键。我认为使用tab比多个空格能够让文件变得更小。而更小的文件能够更快的被解释、上载、下载等等。而使用tab还有一个很大的有点,就是当观看其他人的代码时,你能够自己设置tab键的空格数。我通常使用8个空格长度的tab键设置,但是最近换成了4个空格长度的,呵呵,我把他称为代码的成重新格式化,仅仅是个人的爱好啦。
(2)控制结构
这个很大程度上取决于个人口味。我仍然可以看到很多的控制结构代码不带分支语句造成可读性非常差,如果你使用IF语句时不带分支,不但可读性变差,当其他人修改你的程序时,还会造成很多的bug。请看下例:
不好的例子:
if ($a == 1) echo A was equal to 1;
这是非常难以辨认的。它能够正常工作,但是除了你之外,别人根本不会赞赏这句代码。
有改进的例子:
if ($a == 1)
echo A was equal to 1;
现在至少这句代码可以读懂了,但是仍然没有很好的可维护性。如果当$a==1的时候我希望一个附加的事件发生,或者需要添加分支呢?如果后来的程序员忘记了添加大括弧或者else关键字,那么程序中将出现bug。
完美的例子
if (($a == 1) && ($b==2)) {
echo A was equal to 1;
//很容易的可以添加其他代码
} elseif (($a == 1) && ($b==3)) {
//其他操作
}
请注意在if和elseif后面的空格,这会将本语句和函数调用区分开来,此外,虽然在elseif的执行程序段中没有语句,只有注释,表面上显得多余可是却给以后维护程序的程序员给予了非常方便的提示,并且非常利于添加功能。PHP数据加密


PHP数据加密
数据加密在我们生活中的地位已经越来越重要了,尤其是考虑到在网络上发生的大量交易和传输的大量数据。如果对于采用安全措施有兴趣的话,也一定会有兴趣了解PHP提供的一系列安全功能。在本篇文章中,我们将介绍这些功能,提供一些基本的用法,以便你能够为自己的应用软件中增加安全功能。

预备知识

在详细介绍PHP的安全功能之 前,我们需要花点时间来向没有接触过这方面内容的读者介绍一些有关密码学的基本知识,如果对密码学的基本概念已经非常熟悉,就可以跳 过去这一部分。

密码学可以通俗地被描述为对加/解密的研究和实验,加密是将易懂的资料转换为不易懂资料的过程,解密 则是将不易懂的资料转换为原来易懂资料的过程。不易懂的资料被称作密码,易懂的资料被称作明码。

数据的加/解密都需 要一定的算法,这些算法可以非常地简单,如著名的凯撒码,但当前的加密算法要相对复杂得多,其中一些利用现有的方法甚至是无法破译的 。


PHP的加密功能

只要有一点使用非Windows平台经验的人可能对crypt()也相当熟悉,这一函数完成被称作单向加密的功能,它可以加密一些明码,但不能够将密码转换为原来的明码。尽管从表面上来看这似乎是一个没有什么用处的功能,但它的确被广泛用来保证系统密码的完整性。因为,单向加密的口令一旦落入第三方人的手里,由于不能被还原为明文,因此也没有什么大用处。在验证用户输入的口令时,用户的输入采用的也是单向算法,如果输入与存储的经加密后的口令相匹配,则输入的口信一定是正确的。

PHP同样提供了使用其crypt()函数完成单向加密功能的可能性。我将在这里简要地介绍该函数:

string crypt (string input_string [, string salt])

其中的input_string参数是需要加密的字符串,第二个可选的salt是一个位字串,它能够影响加密的暗码,进一步地排除被称作预计算攻击的可能性。缺省情况下,PHP使用一个2个字符的DES干扰串,如果你的系统使用的是MD5(我将在以后介绍MD5算法),它会使用一个12个字符的干扰串。顺便说一下,可以通过执行下面的命令发现系统将要使用的干扰串的长度:

print "My system salt size is: ". CRYPT_SALT_LENGTH;
系统也可能支持其他的加密算法。crypt()支持四 种算法,下面是它支持的算法和相应的salt参数的长度:

算法 Salt长度
CRYPT_STD_DES 2-character (Default)
CRYPT_EXT_DES 9-character
CRYPT_MD5 12-character beginning with $1$
CRYPT_BLOWFISH 16-character beginning with $2$

用crypt()实现用户身份验证

作为crypt()函数的一个例子,考虑这样一种情况,你希望创建一段PHP脚本程序限制对一个目录的访问,只允许能够提供正确的用户名和口令的用户访问这一目录。我将把资料存储在我喜欢的数据库MySQL的一个表中。下面我们以创建这个被称作members的表开始我们的例子:

mysql>;CREATE TABLE members (
->;username CHAR(14) NOT NULL,
->;password CHAR(32) NOT NULL,
->;PRIMARY KEY(username)
->;);

然后,我们假定下面的数据已经存储在该表中:

用户名 密码
clark keloD1C377lKE
bruce ba1T7vnz9AWgk
peter paLUvRWsRLZ4U

这些加密的口令对应的明码分别是kent、banner和parker。注意一下每个口令的前二个字母, 这是因为我使用了下面的代码,根据口令的前二个字母创建干扰串的:

$enteredPassword.
$salt = substr($enteredPassword, 0, 2);
$userPswd = crypt($enteredPassword, $salt);
// $userPswd然后就和用户名一起存储在MySQL 中

我将使用Apache的口令-应答认证配置提示用户输入用户名和口令,一个鲜为人知的有关PHP的信息是,它可以把Apache 的口令-应答系统输入的用户名和口令识别为$PHP_AUTH_USER和$PHP_AUTH_PW,我将在身份验证脚本中用到这二个变量。花一些时间仔细阅读下 面的脚本,多注意一下其中的解释,以便更好地理解下面的代码:

crypt()和Apache的口令-应答验证系统的应用

$host = "localhost";
$user = "zorro";
$pswd = "hell odolly";
$db = "users";

// Set authorization to False

$authorization = 0;

// Verify that user has entered username and password

if (isset($PHP_AUTH_USER) && isset($PHP_AUTH_PW)) :

mysql_pconnect($host, $user, $pswd) or die("Can/'t connect to MySQL
server!");

mysql_select_db($db) or die("Can/'t select database!");

// Perform the encryption
$salt = substr($PHP_AUTH_PW, 0, 2);
$encrypted_pswd = crypt($PHP_AUTH_PW, $salt);

// Build the query

$query = "SELECT username FROM members WHERE
username = /'$PHP_AUTH_USER/' AND
password = /'$encrypted_pswd/'";

// Execute the query

if (mysql_numrows(mysql_query($query)) == 1) :
$authorization = 1;
endif;

endif;

// confirm authorization

if (! $authorization) :

header(/'WWW-Authenticate: Basic realm="Private"/');
header(/'HTTP/1.0 401 Unauthorized/');
print "You are unauthorized to enter this area.";
exit;

else :

print "This is the secret data!";

endif;

?>;

上面就是一个核实用户访问权限的简单身份验证系统。在使用crypt()保护重要的机密资料时,记住在缺省状态下使用的 crypt()并不是最安全的,只能用在对安全性要求较低的系统中,如果需要较高的安全性能,就需要我在本篇文章的后面介绍的算法。

下面我将介绍另一个PHP支持的函数━━md5(),这一函数使用MD5散列算法,它有几种很有趣的用法值得一提:

混编

一个混编函数可以将一个可变长度的信息变换为具有固定长度被混编过的输出,也被称作“信息文摘”。这是十分有用的,因为一个固定长度的字符串可以用来检查文件的完整性和验证数字签名以及用户身份验证。由于它适合于PHP,PHP内置的md5()混编函数将把一个可变长度的信息转换为128位(32个字符)的信息文摘。混编的一个有趣的特点是不能通过分析混编后的信息得到原来的明码,因为混编后的结果与原来的明码内容没有依赖关系。 即便只改变一个字符串中的一个字符,也将使得MD5混编算法计算出二个截然不同的结果。我们首先来看下表的内容及其相应的结果:
 
使用md5()混编字符串

$msg = "This is some message that I just wrote";
$enc_msg = md5($msg);
print "hash: $enc_msg ";
?>;

结果:

hash: 81ea092649ca32b5ba375e81d8f4972c
注意,结果的长度为32个字符。再来看一下下面的表,其中的$msg的值有了一点 微小的变化:

使用md5()对一个稍微变化的字符串进行混编

//注意,message中少了一个s
$msg = "This is some mesage that I just wrote";
$enc_msg = md5($msg);
print "hash2: $enc_msg

";
?>;

结果:

hash2: e86cf511bd5490d46d5cd61738c82c0c
可以 发现,尽管二个结果的长度都是32个字符,但明文中一点微小的变化使得结果发生了很大的变化,因此,混编和md5()函数是检查数据中微小变 化的一个很好的工具。

尽管crypt()和md5()各有用处,但二者在功能上都受到一定的限制。在下面的部分中,我们将介绍 二个非常有用的被称作Mcrypt和Mhash的PHP扩展,将大大拓展PHP用户在加密方面的选择。

尽管我们在上面的小节中说明了 单向加密的重要性,但有时我们可能需要在加密后,再把密码数据还原成原来的数据,幸运的是,PHP通过Mcrypt扩展库的形式提供了这种可能 性。

Mcrypt
Mcrypt 2.5.7 Unix | Win32
Mcrypt 2.4.7是一个功能强大的加密算法扩展库,它包括有22种算法 ,其中就包括下面的几种算法:

Blowfish RC2 Safer-sk64 xtea
Cast-256 RC4 Safer-sk128
DES RC4-iv Serpent
Enigma Rijndael-128 Threeway
Gost Rijndael-192 TripleDES
LOKI97 Rijndael-256 Twofish
PanamaSaferplus Wake

安装:

在标准的PHP软件包中不包括Mcrypt,因此需要下载它,下载的地址为:ftp://argeas.cs-net.gr/pub/unix/mcrypt/ 。下载后,按照下面的方法进行编译,并把它扩充在PHP中:

下载Mcrypt软件包。
gunzipmcrypt-x.x.x.tar.gz
tar -xvfmcrypt-x.x.x.tar
./configure --disable-posix-threads
make
make install
cd to your PHP directory.
./configure -with-mcrypt=[dir] [--other-configuration-directives]
make
make install

当然了,根据你的 要求和PHP安装时与互联网服务器软件的关系,上面的过程可能需要作适当的修改。


使用Mcrypt

Mcrypt的优点不仅仅 在于其提供的加密算法较多,还在于它可以对数据进行加/解密处理,此外,它还提供了35种处理数据用的函数。尽管对这些函数进行详细介绍 已经超出了这篇文章的范围,我还是要就几个典型的函数作一下简要的介绍。

首先,我将介绍如何使用Mcrypt扩展库对数 据进行加密,然后再介绍如何使用它进行解密。下面的代码对这一过程进行了演示,首先是对数据进行加密,然后在浏览器上显示加密后的数 据,并将加密后的数据还原为原来的字符串,将它显示在浏览器上。

使用Mcrypt对数据进行加、解密


// Designate string to be encrypted
$string = "Applied Cryptography, by Bruce Schneier, is
a wonderful cryptography reference.";

// Encryption/decryption key
$key = "Four score and twenty years ago";

// Encryption Algorithm
$cipher_alg = MCRYPT_RIJNDAEL_128;

// Create the initialization vector for added security.
$iv = mcrypt_create_iv(mcrypt_get_iv_size($cipher_alg,
MCRYPT_MODE_ECB), MCRYPT_RAND);

// Output original string
print "Original string: $string
";

// Encrypt $string
$encrypted_string = mcrypt_encrypt($cipher_alg, $key,
$string, MCRYPT_MODE_CBC, $iv);

// Convert to hexadecimal and output to browser
print "Encrypted string: ".bin2hex($encrypted_string)."

";
$decrypted_string = mcrypt_decrypt($cipher_alg, $key,
$encrypted_string, MCRYPT_MODE_CBC, $iv);

print "Decrypted string: $decrypted_string";

?>;

执行上面的脚本将会产生下面的输出:

Original string: Applied Cryptography, by Bruce Schneier, is a wonderful cryptography reference.

Encrypted string: 02a7c58b1ebd22a9523468694b091e60411cc4dea8652bb8072 34fa06bbfb20e71ecf525f29df58e28f3d9bf541f7ebcecf62b c89fde4d8e7ba1e6cc9ea24850478c11742f5cfa1d23fe22fe8 bfbab5e

Decrypted string: Applied Cryptography, by Bruce Schneier, is a wonderful cryptography reference.

上面的代码中二个最典型的函数是mcrypt_encrypt()和 mcrypt_decrypt(),它们的用途是显而易见的。我使用了“电报密码本”模式,Mcrypt提供了几种加密方式,由于每种加密方式都有可以影响密码安全的特定字符,因此每种模式都需要了解。对于没有接触过密码系统的读者来说,可能对mcrypt_create_iv()函数更有兴趣,尽管对这一函数进行彻底的解释已经超出了本篇文章的范围,但我仍然会提到它创建的初始化向量(hence, iv),这一向量可以使每条信息彼此独立。尽管不是所有的模式都需要这一初始化变量,但如果在要求的模式中没有提供这一变量,PHP就会给出警告信息。


Mhash扩展库

http://sourceforge.net/projects/mhash/

0.8.3版的Mhash扩展库支持12种混编算法,仔细检查Mhash v.0.8.3的头文件mhash.h可以知道,它支持下面的混编算法:

CRC32 HAVAL160 MD5
CRC32B HAVAL192 RIPEMD160
GOST HAVAL224 SHA1
HAVAL128 HAVAL256 TIGER

安装

象Mcrypt一 样,Mhash也没有包括在PHP软件包中,对于非Windows用户而言,下面是安装过程:

下载Mhash扩展库
gunzipmhash-x.x.x.tar.gz
tar -xvfmhash-x.x.x.tar
./configure
make
make install
cd
./configure -with-mhash=[dir] [--other-configuration-directives]
make
make install
象Mcrypt一样 ,根据PHP在互联网服务器软件上的安装方式,可能需要对Mhash进行其他的配置。

对于Windows用户而言, http://www.php4win.de中有一个很好的包括Mhash扩展库在内的PHP软件包。只要下载并进行解压缩,然后根据其中的readme.first文档中的指 令进行安装即可。


使用Mhash

对信息进行混编非常简单,看一下下面的例子:

$hash_alg = MHASH_TIGER;
$message = "These are the directions to the secret fort. Two steps left, three steps right, and cha chacha.";
$hashed_message = mhash($hash_alg, $message);
print "The hashed message is ". bin2hex($hashed_message);
?>;

执行这一段脚本程序将得到下面的输出结果:

The hashed message is 07a92a4db3a4177f19ec9034ae5400eb60d1a9fbb4ade461
在这里使用bin2hex()函数的目的是方便我们理解$hashed_message 的输出,这是因为混编的结果是二进制格式,为了能够将它转化为易于理解的格式,必须将它转换为十六进制格式。

需要 注意的是,混编是单向功能,其结果不依赖输入,因此可以公开显示这一信息。这一策略通常用于让用户比较下载文件和系统管理员提供的文 件,以确保文件的完整性。

Mhash还有其他一些有用的函数。例如,我需要输出一个Mhash支持的算法的名字,由于 Mhash支持的所有算法的名字都以MHASH_开头,因此,可以通过执行如下的代码完成这一任务:

$hash_alg = MHASH_TIGER;
print "This data has been hashed with the".mhash_get_hash_name($hashed_message)."hashing algorithm.";
?>;

得到的输出是:

This data has been hashed with the TIGER hashing algorithm.
关于PHP和加密最后需要注意的一个问题
关于PHP和加密需要注意的最后的一个重要问题是在服务器和客户端之间传输的数据 在传输过程中是不安全的!PHP是一种服务器端技术,不能阻止数据在传输过程中泄密。因此,如果想实现一个完整的安全应用,建议选用 Apache-SSL或其他的安全服务器布置。

结论

这篇文章介绍了PHP最有用的功能之一━━数据加密,不仅讨论了PHP内置 的crypt() 和md5()加密函数,还讨论了用于数据加密的功能强大的扩展库━━Mcrypt和Mhash。在这篇文章最后,我需要指出的是,一个真正安全的PHP应用还应该包括安全的服务器,由于PHP是一种服务器端的技术,因此,在数据由客户端向服务器端进行传输时,它不能保证数据的安全PHP高手之路


PHP是一门高效的网络编程语言,由于它具有编写灵活、运行快速等优点,迅速成为Web程序员的首选语言。前不久的一份权威调查表明,现在已经有31.6%的网站使用PHP作为主要的服务器端编程语言。
但是,要成为一名PHP编程高手却并不容易。并不像很多人想象的那样,只要能够飞快地编写几条简单的代码去解决一个复杂的问题就是PHP编程高手了,真正的PHP高手还需要考虑更多的其它问题。以下三条准则是一名成熟的PHP程序员在编程中应该首先遵循的准则。
1.懒惰是金
2.编写漂亮的代码
3.追求程序的速度,而不是编程的速度
一、懒惰是金
做一个懒惰的程序员吗?这个想法太奇怪了!因为这个世界上最忙碌的人可能就是计算机程序员了。但正是因为程序员太忙了,所以才应该在编程时学会偷懒。
对于一个程序员来说,懒惰的方法有两种:其一,大胆使用现成的别人的程序代码,把这些代码融入到你自己的程序或者项目中去。其二是编写一些有用的代码建立一个函数库,在将来编写程序时可以顺手拈来,省去了许多重复的劳动,自然就可以懒惰一点了。
这两种偷懒的方法都非常适合PHP程序员了。
首先,PHP是在自由开放的环境中诞生和成长的一门语言。在世界各地,有成千上万的程序员,他们一直在为PHP的完美而不断奋斗,他们也愿意和别人分享自己的聪明才智和自己编写的代码。你每天都可以从一些PHP网站、邮件列表、新闻组发现大量的优秀的程序代码。这样说,我并不是鼓励你整天等着让别人为你编写代码,但是你可以“站在伟人的肩膀上”,充分发扬“拿来主义”,聪明地应用别人的程序代码可以节省你大量时间。其次,在PHP中,你可以方便地建立自己的函数库,这样可以在你以后编写程序时省去很多麻烦。
下面笔者为大家介绍几个通用的函数,这些函数有的来自网上的一些开放源代码的项目,有的精选自邮件列表。如果你能把它们加入到你自己的函数库中,迟早你将会发现自己受益无穷。
1.通用数据库处理函数
和其它的CGI函数相比,PHP的优点之一是具有很强大的数据库处理能力。但是,在PHP中,对于不同的数据库都使用一些特定的函数来专门处理,缺少通用的数据库处理函数。这大大降低了程序代码的可移植性,这也为初学编程的朋友带来了很多不便。
在网上,许多程序员都通过封装类解决了这个问题。他们编写了统一的函数用来处理任何流行的数据库——不管是在Linux世界深受欢迎的Mysql还是在 Windows平台上广泛流行的SqlServer。就笔者个人来说,非常喜欢使用这些函数,因为可以直接使用一些简单的诸如"query"、 "next_record"之类的函数,而不需要考虑数据库的连接、数据库句柄这些复杂的东西,更不需要考虑使用的是何种数据库。
如果你需要这些函数,你可以通过访问以下的几个网址而得到:
http://phplib.netuse.de/
http://phpclasses.UpperDesign.com/browse.html/package/20
http://phpdb.linuxbox.com/
2.变量调试函数
PHP程序的调试一直是一件让人头疼的事,它既不像VB等高级语言那样有集成的编译调试环境,也不想Perl那样可以在Linux或者DOS环境下直接运行。其实,我们完全可以通过灵活地使用echo语句来完成对PHP的调试工作。
下面的几个函数可以让你随时查看程序中任何变量的类型及其值。
function ss_array_as_string (&$array, $column = 0) {
$str = "Array(
n";
while(list($var, $val) = each($array)){
for ($i = 0; $i < $column+1; $i++){
$str .= "&nbsp;&nbsp;&nbsp;&nbsp;";
}
$str .= $var. ==>; ;
$str .= ss_as_string($val, $column+1)."
n";
}
for ($i = 0; $i < $column; $i++){
$str .= "&nbsp;&nbsp;&nbsp;&nbsp;";
}
return $str.);
}
function ss_object_as_string (&$object, $column = 0) {
if (empty($object->;classname)) {
return "$object";
}
else {
$str = $object->;classname."(
n";
while (list(,$var) = each($object->;persistent_slots)) {
for ($i = 0; $i < $column; $i++){
$str .= "&nbsp;&nbsp;&nbsp;&nbsp;";
}
global $$var;
$str .= $var. ==>; ;
$str .= ss_as_string($$var, column+1)."
n";
}
for ($i = 0; $i < $column; $i++){
$str .= "&nbsp;&nbsp;&nbsp;&nbsp;";
}
return $str.);
}
}
function ss_as_string (&$thing, $column = 0) {
if (is_object($thing)) {
return ss_object_as_string($thing, $column);
}
elseif (is_array($thing)) {
return ss_array_as_string($thing, $column);
}
elseif (is_double($thing)) {
return "Double(".$thing.")";
}
elseif (is_long($thing)) {
return "Long(".$thing.")";
}
elseif (is_string($thing)) {
return "String(".$thing.")";
}
else {
return "Unknown(".$thing.")";
}
}
需要的时候,在程序中简单地加入下面的一条代码即可查看程序中的所使用的变量(包括数组和对象)的类型和值:
echo ss_as_string($my_variable);
使用下面的语句,我们可以直接查看程序中所有的变量的值:
echo ss_as_string($GLOBALS);
3. 控制Log信息的函数
调试PHP程序的另外一种重要的方法就是查看Log信息。如果能够方便地控制Log信息的级别以及Log信息的显示内容,将会给程序调试带来更多的便利。下面的几个函数可以方便地实现这个功能。
$ss_log_level = 0;
$ss_log_filename = /tmp/ss-log;
$ss_log_levels = array(
NONE =>; 0,
ERROR =>; 1,
INFO =>; 2,
DEBUG =>; 3);
function ss_log_set_level ($level = ERROR) {
global $ss_log_level;
$ss_log_level = $level;
}
function ss_log ($level, $message) {
global $ss_log_level, $ss-log-filename;
if ($ss_log_levels[$ss_log_level] < $ss_log_levels[$level]) {
// 不显示Log信息
return false;
}
$fd = fopen($ss_log_filename, "a+");
fputs($fd, $level. - [.ss_timestamp_pretty().] - .$message."n");
fclose($fd);
return true;
}
function ss_log_reset () {
global $ss_log_filename;
@unlink($ss_log_filename);
}
在上面的函数中,有四个Log级别变量。运行PHP程序时,只有当Log的级别低于预设的级别值时,Log信息才可以被记录和显示出来。例如,在程序中加入如下的一条语句:
ss_log_set_level(INFO);
那么,运行PHP程序时,只有ERROR和INFO级别的LOG信息才能被记录和显示出来,DEBUG级的信息则被忽略了。除此之外,我们还可以设定显示的信息内容,其语句如下:
ss_log(ERROR, "testing level ERROR");
ss_log(INFO, "testing level INFO");
ss_log(DEBUG, "testing level DEBUG");
你也可以随时使用下面的语句清空LOG信息:
ss_log_reset();
4.速度测试函数

为了优化代码,我们需要一种可以测试代码运行时间的方法,从而来选择最优的代码。下面的函数可以测试运行代码所需的时间:
function ss_timing_start ($name = default) {
global $ss_timing_start_times;
$ss_timing_start_times[$name] = explode( , microtime());
}
function ss_timing_stop ($name = default) {
global $ss_timing_stop_times;
$ss_timing_stop_times[$name] = explode(, microtime());
}
function ss_timing_current ($name = default) {
global $ss_timing_start_times, $ss_timing_stop_times;
if (!isset($ss_timing_start_times[$name])) {
return 0;
}
if (!isset($ss_timing_stop_times[$name])) {
$stop_time = explode(, microtime());
}
else {
$stop_time = $ss_timing_stop_times[$name];
}
$current = $stop_time[1] - $ss_timing_start_times[$name][1];
$current += $stop_time[0] - $ss_timing_start_times[$name][0];
return $current;
}
现在可以轻松地检查任何一段代码的执行时间了,甚至我们可以同时使用多个计时器,只需在使用上述的几个函数时设定不同的参数作为计时器的名称就可以了。
5.调试和优化数据库的操作
对于数据库来说,运行速度是至关重要的。尽管很多书籍和文章都讲授了一些快速运行数据库的方法,但是所有的方法都必须经过实践的检验。下面我们将把 PHPLib函数库中的query()函数和上面介绍的几个函数综合起来编写成新的query()函数,和原先的函数相比,这个函数增加了运行时间的监测功能。
function query($Query_String, $halt_on_error = 1) {
$this->;connect();
ss_timing_start();
$this->;Query_ID = @mysql_query($Query_String,$this->;Link_ID);
ss_timing_stop();
ss_log(INFO, ss_timing_current(). Secs - .$Query_String);
$this->;Row = 0;
$this->;Errno = mysql_errno();
$this->;Error = mysql_error();
if ($halt_on_error && !$this->;Query_ID) {
$this->;halt("Invalid SQL: ".$Query_String);
}
return $this->;Query_ID;
}


二、编写漂亮的代码
1.将后台程序与前端程序分开
在编写PHP程序时,有些代码是用来处理一些事务,例如操作数据库、进行数学运算等,而另外的一些代码则只是事务处理的结果显示出来,例如一些使用echo 语句将结果以HTML的格式显示在Web浏览器上的PHP代码以及那些直接嵌入PHP程序的HTML代码。首先我们应该清晰地区分这两种代码,把前者称为后台程序,把后者称为前端程序。
因为PHP是一种嵌入式编程语言,也就是说,所有的PHP代码都可以嵌入到HTML代码之中,这为程序的编写带来了许多便利之处。但是,“物极必反”,如果在一段较长的程序中将PHP代码和HTML代码混合编写,这将使程序杂乱无章,不利于程序的维护和阅读。所以我们需要尽可能地将这些程序中混杂于HTML代码中的PHP代码移植出来,在专门的文件中将这些代码封装成函数,然后在HTML代码中使用 include语句来包含这些文件,在适当的位置调用这些函数即可。
这种做法一方面使HTML代码和PHP代码都简单易读,另一方面因为HTML代码需要不断更新,而这种分离的方法可以确保后台程序不会被破坏。
同前端程序不同,后台程序更多追求的是稳定、结构化,极少更改,所以应该认真地设计和管理。其实,在设计台程序时,投入大量时间是值得的,“现在栽树,以后乘凉”,在以后的设计工作中将可以轻松地使用现在编写的后台程序。
2.灵活使用包含文件
正如前面所说的那样,后台程序应当安排在一系列的包含文件中。包含文件可以通过include语句在需要时动态装入,也可以在php.ini文件中通过使用auto_prepend_file指令预先自动装入。
如果使用后一种方法的话,虽然取得了一劳永逸的好处,但是也有一些缺点值得我们注意。下面的一段代码向我们展示了解析一个庞大的包含文件需要一定的时间:
require(timing.inc);
ss_timing_start();
include(test.inc);
ss_timing_stop();
echo
.ss_timing_current().
;
?>;
在上面的代码中,test.inc是一个1000行的包含文件,运行的结果显示,解析这个包含文件花费了0.6秒钟,对于一个大型网站来说,这个速度并不是可以忽略不记的。
使用包含文件的另外一个缺点是:如果一个文件中的一个语句发生错误,将会使整个网站的PHP程序都无法运行。所以使用起来也及其小心。
其实,对包含文件稍做处理,即可以使包含文件只在需要时进行解析。下面的代码使abc.inc文件只在程序需要时才作解析:
if ( defined( __LIBA_INC) ) return;
define( __LIBA_INC, 1 );
/*
* 代码...
*/
?>;
3.使用面向对象的编程方法
PHP 也是一种面向对象的语言,面向对象的编程方法是优秀的程序员们非常推崇的一种软件设计方法,在PHP编程中可以充分发挥面向对象语言的优势,对编程中的对象进行封装。在前面的代码中,我们使用了面向对象的方法,例如在管理数据库时,我们将query()函数封装进数据库类中,这极大地方便了代码的管理,增加了程序的可读性。
三、追求程序速度,而不是编程的速度
在网站建设中,程序运行速度和网页下载速度都是关系成败的重要因素。作为一名Web程序员,应该更加注意代码的运行速度。下面介绍的几种方法都在不同程度上提高了代码的运行速度。
1.使用内嵌的HTML代码,而不是PHP的echo语句。
因为PHP是一门嵌入式Web编程语言,可以将HTML代码和PHP代码相互嵌入。但是很多程序员担心在HTML代码中过多的使用""嵌入PHP代码会多次调用PHP解释器,从而降低了PHP代码的运行速度,所以宁愿使用PHP的echo语句来输出HTML代码,而不直接使用HTML代码。但事实却恰恰相反。每一个PHP页面只调用一次PHP解释器来解释所有的PHP代码,所以,只在需要时才嵌入PHP代码,而大多数的时候直接使用HTML代码输入结果,不但不会降低程序的运行速度,而且因为减少了对echo语句的解析,往往可以提高代码的运行速度。
下面的一段代码证明了我们的结论。在这段代码中,我们使用了前面介绍的时间测试函数。

使用str-replace而不是ereg-replace
习惯使用Perl进行编程的程序员更加愿意使用ereg_replace完成字符串替换工作,因为在PHP中ereg_replace的用法和Perl中模式匹配的用法相近。但是,下面的这段代码证明,使用str_replace 代替 ereg_replace将可以大大提高代码的运行速度。

测试str_replace和ereg_replace的运行速度

//这段代码测试str_replace的运行速度


emphasis; ?>;

for ($i=0; $i<1000; $i++) {
str_replace(i>;, b>;, $string).
;
}
?>;

//这段代码测试ereg_replace的运行速度

for ($i=0; $i<1000; $i++) {
ereg_replace(<([/]*)i>;, </1b>;, $string).
;
}
?>;

//打印结果

结论

使用str_replace的时间 -

使用ereg_pattern的时间 -
运行上面的代码,得到的结果是:
使用str_replace的时间 - 0.089757
使用ereg_pattern的时间 - 0.248881
从运行的结果我们可以看出使用str_replace替代ereg_replace作为字符串替换函数,极大地提高了代码的运行速度。
3.注意字符串的引用
PHP 和其它很多编程语言一样,可以使用双引号("")来引用字符串,也可以使用单引号()。但是在PHP中,如果使用双引号来引用字符串,那么PHP解析器将首先分析字符串中有没有对变量的引用,有变量的话,将对变量进行替换。如果是单引号,则没有如此复杂——直接将单引号包含起来的所有字符串直接显示出来。显然,在PHP编程中,如果使用单引号引用字符串变量要比使用双引号快速一些。
4.在数据库中避免使用联合操作
比起其它的Web 编程语言来说,PHP的数据库功能十分强大。但是在PHP中数据库的运行仍然是一件十分费时费力的事情,所以,作为一个Web程序员,要尽量减少数据库的查询操作,同时应该为数据库建立适当的索引。另一件值得注意的事情是在用PHP操作数据库时,尽可能不使用多个数据表的联合操作,尽管联合操作可以增强数据库的查询功能,但是却大大增加了服务器的负担。
为了说明这个问题,我们可以看看下面的这个简单的例子。
我们在数据库中创建了两个数据表foo和big_foo。在数据表foo中,只有一个字段,包含了从1-1000之间的所有自然数。数据表big_foo同样只有一个字段,但包含了从1-1,000,000之间的全部自然数。所以,从大小上说,big_foo等于foo与它自身进行了联合操作。
$db->;query("select * from foo");
0.032273 secs
$db->;next_record();
0.00048999999999999 secs
$db->;query("insert into foo values (NULL)");
0.019506 secs
$db->;query("select * from foo as a, foo as b");
17.280596 secs
$db->;query("select * from foo as a, foo as b where a.id >; b.id");
14.645251 secs
$db->;query("select * from foo as a, foo as b where a.id = b.id");
0.041269 secs
$db->;query("select * from big_foo");
25.393672 secs
从上面操作结果我们可以发现,对于两个有1000条记录的数据表进行联合,其速度并不比对一个1000000条纪录的大型数据表单独进行操作快多少。
5.注意include与require的区别
在PHP 变成中,include()与require()的功能相同,但在用法上却有一些不同,include()是有条件包含函数,而require()则是无条件包含函数。例如在下面的一个例子中,如果变量$somgthing为真,则将包含文件somefile:
if($something){
include("somefile");
}
但不管$something取何值,下面的代码将把文件somefile包含进文件里:
if($something){
require("somefile");
}
下面的这个有趣的例子充分说明了这两个函数之间的不同。
$i = 1;
while ($i < 3) {
require("somefile.$i");
$i++;
}
在这段代码中,每一次循环的时候,程序都将把同一个文件包含进去。很显然这不是程序员的初衷,从代码中我们可以看出这段代码希望在每次循环时,将不同的文件包含进来。如果要完成这个功能,必须求助函数include():
$i = 1;
while ($i < 3) {
include("somefile.$i");
$i++;
}
6.注意echo和print的区别
PHP中echo和print的功能也基本相同,但是两者之间也有细微差别。在PHP代码中可以把print作为一个普通函数来使用,例如执行下面的代码后变量$res的值将为1。
$ret = print "Hello World";
这意味着print可用在一些复杂的表达式中,而echo则不行。同样,在代码中echo语句的运行速度要略微快于print语句,因为echo语句不要求返回任何数值.事实上呢,php的高手之路终点就是Linux C高手之路,要最终成为PHP的高手,就需要学会使用C来开发PHP的扩展模块,以达到最好的效率和性能,包括一些系统调用和复杂的业务逻辑处理,最多的就是网络安全等方面的处理。我们曾经做过很多这样类似的东西,效果非常明显,编译到php后在php里面调用速度和性能,再有就是安全性也提高了


要最终成为PHP的高手,就需要学会使用C来开发PHP的扩展模块
这样的确算高手
事实上呢,php的高手之路终点就是Linux C高手之路
但是高手不一定只有这条路,我把高手定义为:可以写出对大多数人极具使用价值的软件的人,从写代码的技术上说,可以长期的、稳定的编写高质量代码的人,这种人也算高手 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值