首页 理论教育 PHP单例模式的常见应用场景

PHP单例模式的常见应用场景

时间:2023-11-02 理论教育 版权反馈
【摘要】:10.当你只需要一个对象时,使用单例模式在PHP中相当常见的一种情形时,我们只需要创建一个对象一次,然后在我们的整个程序中使用它。

PHP单例模式的常见应用场景

1.如何正确地创建一个网站的Index页面

创建每一个网站时,建立网站的index页面是首要做的事情之一。如果你是一个PHP新手,在编写index页面时典型的做法是只对index页面所需的内容进行编程,其他链接创建另一个页面。不过,如果想学习一种更高效的方式来实现PHP编程,可以采用“index.PHP page=home”模式,许多网站都在采用这种模式。

2.使用Request Global Array抓取数据

实际上我们没有任何理由使用$_GET和$_POST数组来抓取数值。$_REQUEST这个全局数组能够让你获取一个get或form请求。因此,多数情况下解析数据的更高效代码大体如下:

$action=isset($_REQUEST['action'])$_REQUEST['action']:0;

3.利用var_dump进行PHP代码调试

如果你在寻找PHP调试技术,我必须说var_dump应该是你要找的目标。在显示PHP信息方面这个命令可以满足你的所有需要。而调试代码的多数情况与得到PHP中的数值有关。

4.PHP处理代码逻辑,Smarty处理展现层

Smarty是一个使用PHP写出来的模板PHP模板引擎,是目前业界最著名的PHP模板引擎之一。它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与HTML代码混杂在一起PHP代码逻辑分离。简单地讲,目的就是要使PHP程序员前端人员分离,使程序员改变程序的逻辑内容不会影响到前端人员的页面设计,前端人员重新修改页面不会影响到程序的程序逻辑,这在多人合作的项目中显得尤为重要。

5.的确需要使用全局数值时,创建一个Config文件

动辄创建全局数值是一种糟糕的做法,不过有时候实际情况的确又需要这么做。对于数据库表或数据库连接信息使用全局数值是一个不错的想法,但不要在你的PHP代码中频繁使用全局数值。另外,更好的一种做法是把你的全局变量存放在一个config.PHP文件中。

6.如果未定义,禁止访问!

如果你正确的创建了页面,那么任何其他人没有理由访问index.PHP或home.PHP之外的index.PHP页面。一旦index.PHP被访问后,你可以通过获得变量的方式来打开需要的页面。你的index页面应该包含类似的以下代码:

define('yourPage',1);

然后,其他页面应该包含:

if(!defined('yourPage'))die('Access Denied');

这么做的目的是防止直接访问你的其他PHP页面。这样,任何试图不通过index.PHP访问其他网页的人,将得到“访问被拒绝”的消息。

7.创建一个数据库类

如果你正在进行数据库编程(在PHP中非常常见的任务),一个不错的想法是创建一个数据库类来处理任何数据库管理功能。示例代码如下:

这个函数仅接收一个查询语句并对其执行。它还处理可能出现的任何错误。你还可以在这儿包含审核代码,不过我更喜欢使用一个类似的审核函数:

8.一个PHP文件处理输入,一个class.PHP文件处理具体功能

不让代码变得混乱的一个重要方法是:获取用户输入后,将其重定向到其他函数来进行处理。原理非常简单,PHP文件获得我们需要的任何输入,然后将其执行重定向到类文件中的一个函数。举例来讲,假设有一个类似“index.PHP page=profile&action=display”的URL。由profile.PHP来检索该网址并得到操作是“display”。然后使用一个简单的switch函数,我们来执行真正地显示函数:

如上所示,我使用了一个消息类,然后开始进行switch检查。$message只是被类中的调用函数使用的一个对象。

9.了解你的SQL语句,并总是对其审查

任何PHP网站中最重要的部分有99%的可能是数据库。因此,你需要非常熟悉如何正确地使用sql。学会关联表和更多高级技术。下面将展示一个使用MySQL的函数示例。

首先,我们对用户输入进行检查(通过一个GET变量传递消息id),然后我们执行我们的SQL命令。

10.当你只需要一个对象时,使用单例模式

在PHP中相当常见的一种情形时,我们只需要创建一个对象一次,然后在我们的整个程序中使用它。一个很好的例子就是smarty变量,一旦被初始化后就可以在任何地方使用。这种情形的一个很好实现方案就是单例模式。示例代码如下:

注意,我们拥有一个全局smarty变量(该示例中它在config.PHP中被初始化),如果它的值为0,我们将创建一个新smarty对象。否则,它意味着该对象已经被创建,我们只需要返回它。

11.高速缓存动态PHP页面

缓存整个网站,你需要考虑哪些网页获得高流量,哪些页面做一些数据库请求。静态HTML页面不需要缓存,因此有效的缓存对于开发是很重要的。

12.PHP安全登录提示和技巧

每一个网站在互联网上面临着类似的黑客威胁。如果不正确实施的保安措施,特别是当涉及最敏感的数据比如登录页面。因此,有必要更好地确认我们做的措施被认为是真正的安全的。在这篇文章中,讲解关于PHP安全登录提示和技巧。

13.PHP读取Excel工作表

为了实现这一目标,使用开源工具PHPExcelReader。它为我们提供必要的API,使我们能够在PHP读取Excel工作表。

14.HTML Scrapper in PHP

有时我们要提取远程网站页面的HTML内容,这种技术被称为HTML scrapper。

15.PHP文件上传

这里uploader.PHP是一个简单的脚本,将该文件上载到PHP的临时缓存目录然后将它移到一个预先设定的目录。

16.PHP从源到目的地的复制目录

要复制目录源到目标目录,你将需要扫描的源目录中的所有文件和目录,并复制到的目标。

17.使用PHP GzipCSS文件

使用Gzip和PHP,我们可以最大限度地减少CSS文件大小。这种技术是一种功能强大且简单的方法来减少网页下载的速度以加快您的网站。

18.Backup Database XML PHP

备份数据是非常重要的。核心部分就是数据库。想象一下,如果失去了所有的数据库中的数据-这将是悲剧性的。这里的一个的PHP片段,使您的数据库以XML输出。

19.PHP的HTTP认证

20.PHP批量取得checkbox的值

(1)命名

<input type='checkbox'name='checkbox[]'value=$dwmyrow[banzhu]/>

(2)使用

当计划当作sql指令的一部分时:如果参与控制的字段是数值型的,则

if(!empty($_POST['checkbox'])){

$expr=join(",",$_POST['checkbox']);

$sql="select*from tbl_name where field in($expr)";

}

如果参与控制的字段是数值型的,则

if(!empty($_POST['checkbox'])){

$expr="'".join("','",$_POST['checkbox']).".";

$sql="select*from tbl_name where field in($expr)";

}

21.PHP判断Form表单是否提交

$action=$HTTP_POST_VARS["Button1"];

if($action=="提交"){

//执行表单操作

}else{

//读取默认值

}

22.PHP获取字符长度

strlen($myrow[1])

23.PHP Url转向

Header("Location:".$_SERVER["HTTP_REFERER"]);

24.PHP超全局对象

<?php

$a=1;

$b=2;

function Sum(){

$GLOBALS["b"]=$GLOBALS["a"]+$GLOBALS["b"];

}

Sum();

echo $b;

?>

25.PHP表单取值

如果mothod="get"就用$_GET["test"]代替$test如果mothod="post"就用$_POST["test"]代替$test

26.PHP取得当前IP

<=$HTTP_SERVER_VARS["REMOTE_ADDR"]>

27.PHP取得当前时间

<php

echo date("Y-m-d G:i:s");

?>

date("Y年m月d日")Date("Y-n-j")

28.使用一个SQL注射备忘单

一个基本的原则就是,永远不要相信用户提交的数据。另一个规则就是,在你发送或者存储数据时对它进 行转义(escape)。可以 总 结为:filter input,escape output(FIEO).输入过滤,输出转义。通常导致SQL注射漏洞的原因是没有对输入进行过滤,如下语句:

代码如下:

<?php

$query="SELECT*FROM users WHERE name='{$_GET['name']}'";

?>

在这个例子中,$_GET['name']来自用户提交的数据,既没有进行转义,也没有进行过滤,对于转义输出,你要记住用于你程序外部的数据需要被转义,否则,它可能被错误地解析。相反,过滤输入能确保数据在使用前是正确的.对于过滤输入,你要记住,在你程序外部的原始数据需要被过滤,因为它们是不可信任的。如下例子演示了输入过滤和输出转义:

代码如下:

<?php

//Initialize arrays for filtered and escaped data,respectively.

$clean=array();

$sql=array();

//Filter the name.(For simplicity,we require alphabetic names.)

if(ctype_alpha($_GET['name'])){

$clean['name']=$_GET['name'];

}else{

//The name is invalid.Do something here.

}

//Escape the name.

$sql['name']=mysql_real_escape_string($clean['name']);

//Construct the query.

$query="SELECT*FROM users WHERE name='{$sql['name']}'";

?>

另一个有效防止SQL注射的方法是使用prepare语句,如:

代码如下:

<?php

//Provide the query format.

$query=$db->prepare('SELECT*FROM users WHERE name=:name');

//Provide the query data and execute the query.

$query->execute(array('name'=>$clean['name']));

?>

29.了解比较运算符之间的不同

你使用strpos()来检测在一个字符串中是否存在一个子串(如果子串没有找到,函数将返回FALSE),结果可能会导致错误:

代码如下:

<?php

$authors='Chris & Sean';

if(strpos($authors,'Chris')){

echo'Chris is an author.';

}else{

echo'Chris is not an author.';

}

?>

上例中,由于子串处于最开始的位置,因此strpos()函数正确地返回了0,表明子串处于字符串中最开始的位置。然后,因为条件语句会把结果当成Boolean(布尔)类型的,因此0就被PHP给计算成了FALSE,最终导致条件语句判断失败。当然,这个BUG可以用严格的比较语句来修正:

代码如下:

<?php

if(strpos($authors,'Chris')!==FALSE){

echo'Chris is an author.';

}else{

echo'Chris is not an author.';

}

?>

30.减少else

在你使用变量前总是要先初始化它们。考虑如下一个用来根据用户名来检测用户是否是管理员的条件语句:

代码如下:

<?php

if(auth($username)=='admin'){

$admin=TRUE;

}else{

$admin=FALSE;

}

?>

这个看起来似乎足够安全,因为看一眼就很容易理解。想象一下有一个更复杂一点的例子,它为name和email同时设置变量,为方便起见:

代码如下:

<?php

if(auth($username)=='admin'){

$name='Administrator';

$email='admin@example.org';

$admin=TRUE;

}else{

/*Get the name and email from the database.*/

$query=$db->prepare('SELECT name,email FROM users WHERE username=:username');

$query->execute(array('username'=>$clean['username']));

$result=$query->fetch(PDO::FETCH_ASSOC);

$name=$result['name'];

$email=$result['email'];

$admin=FALSE;

}

?>

因为$admin还是明确地被设置为TRUE or FALSE,似乎一切都完好。但是,如果另一个开发者后来在代码里加了一个elseif语句,很可能他会忘记这回事:

代码如下:

<?php

if(auth($username)=='admin'){

$name='Administrator';

$email='admin@example.org';

$admin=TRUE;

}elseif(auth($username)=='mod'){

$name='Moderator';

$email='mod@example.org';

$moderator=TRUE;

}else{

/*Get the name and email.*/

$query=$db->prepare('SELECT name,email FROM users WHERE username=:username');

$query->execute(array('username'=>$clean['username']));

$result=$query->fetch(PDO::FETCH_ASSOC);

$name=$result['name'];$email=$result['email'];

$admin=FALSE;$moderator=FALSE;

}

?>

如果一个用户提供一个能够触发elseif条件的用户名(username),$admin没有被初始化,这可能会导致不必要的行为,或者更糟糕的情况,一个安全漏洞。另外,一个类似的情况对于$moderator变量来说同样存在,它在第一个条件中没有被初始化。通过初始化$admin和$moderator,这是完全很容易避免这一情况的发生的:

代码如下:

<?php

$admin=FALSE;

$moderator=FALSE;

if(auth($username)=='admin'){

$name='Administrator';

$email='admin@example.org';

$admin=TRUE;

}elseif(auth($username)=='mod'){

$name='Moderator';(www.xing528.com)

$email='mod@example.org';$moderator=TRUE;

}else{

/*Get the name and email.*/

$query=$db->prepare('SELECT name,email FROM users WHERE username=:username');

$query->execute(array('username'=>$clean['username']));

$result=$query->fetch(PDO::FETCH_ASSOC);

$name=$result['name'];

$email=$result['email'];

}

?>

不管剩下的代码是什么,现在已经明确了$admin值为FALSE,除非它被显式地设置为其他值。对于$moderator也是一样的。最坏的可能发生的情况就是,在任何条件下都没有修改$admin或$moderator,导致某个是administrator或moderator的人没有被当作相应的administrator或moderator。如果你想shortcut something,并且你看到我们的例子有包含有else觉得有点失望。我们有一个bonus tip你可能会感兴趣的。我们并不确定它可以被认为是a shortcut,但是我们希望它仍然是有帮助的。考虑一下一个用于检测一个用户是否被授权查看一个特定页面的函数:

代码如下:

<?php

function authorized($username,$page){

if(!isBlacklisted($username)){

if(isAdmin($username)){return TRUE;

}elseif(isAllowed($username,$page)){

return TRUE;

}else{

return FALSE;

}

}else{

return FALSE;

}

}

?>

这个例子是相当的简单,因为只有三条规则需要考虑:administrators总是被允许访问的,处于黑名单的永远是禁止访问的,isAllowed()决定其他人是否有权访问。(还有一个特例是:当一个administrator处于黑名单中,但这似乎是不太可能的事,所以我们这里直接忽视这种情况)。我们使用函数来做这个判断以保持代码的简洁然后集中注意力到业务逻辑上去。如:

代码如下:

<?php

function authorized($username,$page){

if(!isBlacklisted($username)){

if(isAdmin($username)||isAllowed($username,$page)){

return TRUE;

}else{

return FALSE;

}

}else{

return FALSE;

}

}

?>

事实上,你可以精减整个函数到一个复合条件:

代码如下:

<?php

function authorized($username,$page){

if(!isBlacklisted($username)&&(isAdmin($username)||isAllowed($username,$page)){

return TRUE;

}else{

return FALSE;

}

}

?>

最后,这个可以被减少到只有一个return:

代码如下:

<?php

function authorized($username,$page){

return(!isBlacklisted($username)&&(isAdmin($username)||isAllowed($username,$page));

}

?>

如果你的目标是誊清代码的行数,那么这样你做到的。但是,你要注意到,我们在用isBlacklisted(),isAdmin()和isAllowed(),这取决于参与这些判断的东西,减少代码到只剩下一个复合条件可能不吸引人。这下说到我们的小技巧上了,一个“立即返回”函数,所以,如果你尽快返回,你可以很简单地表达这些规则:

代码如下:

<?php

function authorized($username,$page){

if(isBlacklisted($username)){

return FALSE;

}if(isAdmin($username)){return TRUE;

}return isAllowed($username,$page);

}

?>

这个例子使用了更多行数的代码,但是它是非常简单和不惹人注意的。更重要的是,这个方法减少了你必须考虑的上下文的数量。

31.静态调用的成员一定要定义成static

PHP 5引入了静态成员的概念,作用和PHP 4的函数内部静态变量一致,但前者是作为类的成员来使用。静态变量和Ruby的类变量(class variable)差不多,所有类的实例共享同一个静态变量。

<?php

class foo{

function bar(){

echo'foobar';

}

}

$foo=new foo;

//instance way$foo->bar();

//static wayfoo::bar();

?>

静态地调用非static成员,效率会比静态地调用static成员慢50-60%。主要是因为前者会产生E_STRICT警告,内部也需要做转换。

32.使用类常量

PHP 5新功能,类似于C++的const。使用类常量的好处是:编译时解析,没有额外开销;杂凑表更小,所以内部查找更快;类常量仅存在于特定「命名空间」,所以杂凑名更短-代码更干净,使除错更方便。

33.不要使用require/include_once

require/include_once每次被调用的时候都会打开目标文件!如果用绝对路径的话,PHP 5.2/6.0不存在这个问题。新版的APC缓存系统已经解决这个问题文件I/O增加=>效率降低如果需要,可以自行检查文件是否已被require/include。

34.不要调用毫无意义的函数

有对应的常量的时候,不要使用函数。

2<?php

php_uname('s')==PHP_OS;

PHP_version()==PHP_VERSION;

PHP_sapi_name()==PHP_SAPI;

?>

虽然使用不多,但是效率提升大概在3500%左右。

35.最快的Win32检查

<?php

$is_win=DIRECTORY_SEPARATOR=='//';

?>

不用函数,Win98/NT/2000/XP/Vista/Longhorn/Shorthorn/Whistler...通用

36.时间问题

你如何在你的软件中得知现在的时间?不过总归会调用函数。现在好了,用$_SERVER['REQUEST_TIME'],不用调用函数,又省了。

37.加速PCRE

能不用正则,就不用正则,在分析的时候仔细阅读手册「字符串函数」部分。有没有你漏掉的好用的函数?例如:strpbrk()strncasecmp()strpos()/strrpos()/stripos()/strripos()

38.加速strtr

如果需要转换的全是单个字符的时候,用字符串而不是数组来做strtr:

<?php

$addr=strtr($addr,"abcd","efgh");

//good

$addr=strtr($addr,array('a'=>'e',));

//bad

?>

效率提升:10倍。

39.不要做无谓的替换

即使没有替换,str_replace也会为其参数分配内存,很慢!解决办法:用strpos先查找(非常快),看是否需要替换,如果需要,再替换。效率:如果需要替换:效率几乎相等,差别在0.1%左右。如果不需要替换:用strpos快200%。

40.@操作符不要滥用

虽然@看上去很简单,但是实际上后台有很多操作。用@比起不用@,效率差距:3倍。特别不要在循环中使用@,在5次循环的测试中,即使是先用error_reporting(0)关掉错误,在循环完成后再打开,都比用@快。

41.善用strncmp

当需要对比「前n个字符」是否一样的时候,用strncmp/strncasecmp,而不是substr/strtolower,更不是PCRE,更千万别提ereg。strncmp/strncasecmp效率最高(虽然高得不多)。

42.慎用substr_compare

按照上面的道理,substr_compare应该比先substr再比较快了。答案是否定的,除非无视大小写的比较,比较较大的字符串。

43.不要用常量代替字符串

需要查询杂凑表两次,需要把常量名转换为小写(进行第二次查询的时候),生成E_NOTICE警告,会建立临时字符串效率差别:700%。

44.不要把count/strlen/sizeof放到for循环的条件语句中

2<?php

for($i=0,$max=count($array);$i<$max;++$i);

>效率提升相对于:count 50%-strlen 75%

45.短的代码不一定快

<?php

//longest

if($a==$b){

$str.=$a;

}else{

$str.=$b;}

//longer

if($a==$b){

$str.=$a;}$str.=$b;

//short

$str.=($a==$b $a:$b);

?>

你觉得哪个快?效率比较:longest:4.27,longer:4.43,short:4.76

再看一个例子:

<?php

//original

$d=dir('.');

while(($entry=$d->read())!==false){

if($entry=='.'||$entry=='..'){

continue;

}}

//versus

glob('./*');

//versus(include.and..)

scandir('.');

?>

哪个快?效率比较:original:3.37,glob:6.28,scandir:3.42,original without OO:3.14,SPL(PHP5):3.95

46.提高PHP文件访问效率

需要包含其他PHP文件的时候,使用完整路径,或者容易转换的相对路径。

<?php

include'file.PHP';

//bad approach

incldue'./file.PHP';

//good

include'/path/to/file.PHP';

//ideal

?>

47.物尽其用

PHP有很多扩展和函数可用,在实现一个功能的之前,应该看看PHP是否有了这个功能?是否有更简单的实现?

<?php

$filename="./somepic.gif";

$handle=fopen($filename,"rb");

$contents=fread($handle,filesize($filename));

fclose($handle);

//vs.much simpler

file_get_contents('./somepic.gif');

?>

48.关于引用的技巧

+简化对复杂结构数据的访问,优化内存使用。

<?php

$a['b']['c']=array();

//slow 2 extra hash lookups per access

for($i=0;$i<5;++$i)

$a['b']['c'][$i]=$i;

//much faster reference based approach

$ref=& $a['b']['c'];

for($i=0;$i<5;++$i)

$ref[$i]=$i;?>

<?php

$a='large string';

//memory intensive approach

function a($str){

return $str.'something';

}

//more efficient solution

function a(&$str){

$str.='something';

}

?>

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈