深入理解php高級(jí)技巧、面向?qū)ο笈c核心技術(shù)原書(shū)_第1頁(yè)
深入理解php高級(jí)技巧、面向?qū)ο笈c核心技術(shù)原書(shū)_第2頁(yè)
深入理解php高級(jí)技巧、面向?qū)ο笈c核心技術(shù)原書(shū)_第3頁(yè)
深入理解php高級(jí)技巧、面向?qū)ο笈c核心技術(shù)原書(shū)_第4頁(yè)
深入理解php高級(jí)技巧、面向?qū)ο笈c核心技術(shù)原書(shū)_第5頁(yè)
免費(fèi)預(yù)覽已結(jié)束,剩余102頁(yè)可下載查看

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1PHP與初學(xué)者相比,高級(jí)PHP以理解的特性中獲益。舉例來(lái)說(shuō),盡管我們已經(jīng)知道如何使用數(shù)組,但是對(duì)數(shù)組未必精通:如創(chuàng)建數(shù)據(jù)、對(duì)其進(jìn)行排序等操作。或許我們已經(jīng)知道如何編寫自定義函數(shù),但是不一定知道如何使用遞歸以及靜態(tài)變量。本章將討論這類問(wèn)題以及其他一些非基礎(chǔ)的概念,比如原的語(yǔ)法以及 數(shù)由于數(shù)組的強(qiáng)大和靈活性,使其在PHP編程中得到了廣泛的應(yīng)用。對(duì)于高級(jí)應(yīng)用來(lái)說(shuō),數(shù)組經(jīng)常用來(lái)解決其他第一個(gè)例子將展示如何對(duì)一個(gè)數(shù)組進(jìn)行排序。這是一lis, 在PHP

圖1-1數(shù)組的應(yīng)用方式之sort()、ksort等相關(guān)函數(shù)。使用它們,可以對(duì)一維數(shù)組進(jìn)行關(guān)鍵字排序、按值排序、逆排序$a=array('key1'=>23,'key2'=>'this'),array('key1'=>894,'key2=>'that')PHP5.4中新增了數(shù)組的縮寫語(yǔ)法,這為創(chuàng)建數(shù)組提供了一種簡(jiǎn)便的方式。使用數(shù)組的縮寫語(yǔ)法的方式也很簡(jiǎn)單,將調(diào)用array()函數(shù)替換為方括號(hào)即可。舉例://Old$a=array();//$b=array('this'=>//New$a=[];//$b=['this'=>這是一個(gè)簡(jiǎn)單的二維數(shù)組(數(shù)組的元素本身也是數(shù)組key1(數(shù)值排序)或key2(字符順序排序。為了對(duì)數(shù)組進(jìn)行排序,我們需要定義自己的排序函數(shù),然后告訴PHP在調(diào)用usort()、uasort()或者uksort()的時(shí)候使用我們的自定義排序函數(shù)。它必須接收兩個(gè)參數(shù),并且返回一個(gè)值表示哪個(gè)參數(shù)應(yīng)該排面。負(fù)數(shù)或者false意味著第一個(gè)參數(shù)應(yīng)該排在第二個(gè)參數(shù)前面。正數(shù)或者true則表示第二個(gè)參數(shù)應(yīng)該排面。如果值為0,則舉例來(lái)說(shuō) 為了對(duì)前面提到的數(shù)組根據(jù)第一個(gè)關(guān)鍵字進(jìn)行排序,我們的自定義排序函數(shù)可以寫成這樣:functionasc_number_sort($x,returntrue;{return}elsereturn}}PHP中這樣使用它(1-2usort($a,PHP會(huì)把內(nèi)層數(shù)組不斷地發(fā)送給這個(gè)函數(shù),從而將其排序。如果我們想要了解細(xì)節(jié),那么可以輸出函數(shù)里被比較的數(shù)值,我們可以看到自定義排序函數(shù)是如何被調(diào)用的,如圖1-3所示。Usort()函數(shù)根據(jù)數(shù)值進(jìn)行排序,但是它不保存關(guān)鍵字(對(duì)于外層數(shù)組來(lái)說(shuō)。當(dāng)我們使用uasort()函數(shù)時(shí),關(guān)鍵字就會(huì)被保存。當(dāng)我們使用uksort()函數(shù)時(shí),排序?qū)⒒?圖1-2數(shù)組根據(jù)數(shù)值排序 圖1-3輸出$x['key1']和$y['key1']的如果想對(duì)前例數(shù)組的第二個(gè)關(guān)鍵字進(jìn)行排序,就需要對(duì)字符串進(jìn)行比較。相關(guān)代碼如圖1-4functionstring_sort($x,{return?}usort($a,1-4key2按字母進(jìn)行排()在文本編輯器或集成開(kāi)發(fā)環(huán)境(IDE)中創(chuàng)建一個(gè)PHP,命名為sort.php。該文件以一段HTML代碼開(kāi)始,如1.1所示。<!doctype<html??<link?<?php#Script1.1-1.1這個(gè)定義了一個(gè)二維數(shù)組 <!doctype<html<metacharset="utf-<title>SortingMultidimensional<linkrel="stylesheet"<?php#Script1.1-sort.php/*Thispagecreatesamultidimensional*ofnamesand*Thearrayisthensorted*oncebynameandonceby//Createthe//Array//studentID=>array('name'=>'Name','grade'=>$students= 256=>array('name'=>'Jon','grade'=> 2=>array('name'=>'Vance','grade'=>9=>array('name'=>'Stephen','grade'=>364=>array('name'=>'Steve','grade'=>68=>array('name'=>'Rob','grade'=> //Namesortingreturnstrcasecmp($x['name'],31//Gradesorting//SortinDESCENDINGfunctiongrade_sort($x,$y)return($x['grade']<37//Printthearrayasuasort($students,echo'<h2>ArraySortedByName</h2><pre>'.print_r($students,1).'</pre>';//Sortbyuasort($students,echo'<h2>ArraySortedByGrade</h2><pre>'.print_r($students,1).'</pre>'; 可能你注意到了我在本所有的示例中使用了HTML5,即便這不會(huì)對(duì)PHP代碼產(chǎn)生任何影響。我還使用了一個(gè)來(lái)自HTML5Boilerplate(/)的簡(jiǎn)單 $students=256=>array('name'=>?'grade'=>?'grade'=>?'grade'=>364=>array('name'=>?'grade'=>68=>array('name'=>?'grade'=>外層數(shù)組$students有5IDfunctionname_sort($x,{return?}trcaecmp()函數(shù)會(huì)返回一個(gè)數(shù)值—負(fù)數(shù)、0或者正數(shù),表示這兩個(gè)字符的相似程度?;匾粋€(gè)數(shù),表示二個(gè)符串。果返回0則表示兩個(gè)字符串完全等。unctiongrade_srt($x,{return($x['grade]?$y['grade}這個(gè)例子類似前面介紹的示例程序,不過(guò)更加精簡(jiǎn)。一個(gè)明顯的區(qū)別是這個(gè)例子會(huì)進(jìn)行降序排序,將最好的成績(jī)排在最前面。這很容易實(shí)現(xiàn):把比較操作符從大于修改為小于就可true值,這也就意味著第二個(gè)參數(shù)應(yīng)該排在順序列表的前面。echo'<h2>ArrayAsIs</h2><pre>'使用print_r()函數(shù)來(lái)快速打印出數(shù)組的內(nèi)容。為了提高可讀性,打印的內(nèi)容將使用<pre>進(jìn)行包裹uasort($students,?($students,1).因?yàn)檫@里使用了uasort()函數(shù),所以關(guān)鍵字,也就是學(xué)生的ID,不會(huì)丟失,如圖1-5所示。如果只是使用了函數(shù)usort(),排序結(jié)果將會(huì)把這些關(guān)鍵字丟掉,如圖1-6所示。uasort($students,?Grade</h2><pre>'.?($students,1).保存文件為sort.php,將其放置于你的 圖1-5數(shù)組按照排 圖1-6參看1.1,如果 圖1-7數(shù)組根據(jù)成績(jī)降序排使用函數(shù)uasort將會(huì)導(dǎo)致關(guān)如果我們回想一下,大多數(shù)數(shù)據(jù)庫(kù)查詢都返回一個(gè)數(shù)組,如圖1-8所示。如果查詢結(jié)果只是作為一個(gè)整體發(fā)送,那么這種數(shù)組的結(jié)構(gòu)并不會(huì)讓代碼變得復(fù)雜。但如果想對(duì) 圖1-8從數(shù)據(jù)庫(kù)中選擇包含多個(gè)字段的多條記錄就產(chǎn)生了一個(gè)數(shù)eb務(wù)列表系統(tǒng)。如果任務(wù)列表是一維的,就不會(huì)有什么難度。但是如果列表是可以嵌套的,其中每一項(xiàng)任務(wù)又可以有很多個(gè)步驟,那么就會(huì)得到一種樹(shù)形的結(jié)構(gòu),其中每個(gè)分支都可以具1-9所示。SubsubtaskSubsubtaskSubtaskAnotherMustDoSubtaskSubtaskCREATETABLEtaskstask_idINTUNSIGNEDNOT?parent_idINTUNSIGNEDNOT?DEFAULTdate_addedTIMESTAMPNOTNULL,pletedTIMESTAMP,PRIMARYKEY(task_id),INDEXaddedINDEXcompleted

1-9嵌套的工作列表在結(jié)構(gòu)上類似task10MustDotask10MustDo20Another30MyNew42Subtask52Subtask62Subtask Subsubtask數(shù)據(jù)類型VARCHAR(100);如果需要更長(zhǎng)的描述,可以把它定義為文本類型(texttype)。最后項(xiàng)都有一個(gè)parent_id一個(gè)子任務(wù),那么它的parent_id的值就是對(duì)應(yīng)的列表項(xiàng)的值,如圖1-10所示。如果這個(gè)列表項(xiàng)不是子任務(wù),它的

1-10這個(gè)表格展示的數(shù)據(jù)和1-81-圖的中一樣。在字段task_id和parent_id之間有偽外鍵和主鍵的對(duì)應(yīng)關(guān)系0。這是為了實(shí)現(xiàn)靈活的嵌套結(jié)構(gòu)的簡(jiǎn)單設(shè)置,但是在PHP中的處理會(huì)花費(fèi)一些功夫。表。接下來(lái)的內(nèi)容介紹如何在這個(gè)表中增加新任務(wù)的PHP。在本章接下來(lái)的幾個(gè)在你的文本編輯器或者集成開(kāi)發(fā)環(huán)境中新建一段PHP,命名為php,以下面的HTML代碼開(kāi)始,如1.2所示<!doctype<html<title>Adda<link?<?php#Script1.2-$dbc=本例中使用的是MySQL,而且在代碼中使用了改進(jìn)的MySQL函數(shù)。你需要改變對(duì)應(yīng)的.2 使用以下向數(shù)據(jù)庫(kù)中添加任務(wù)。利用下拉菜單可以將任務(wù)歸于其他任務(wù)執(zhí)行<!doctype<html<metacharset="utf-<title>Adda<linkrel="stylesheet"<?php#Script1.2-add_task.php*Thepagebothdisplaysandhandlesthe//Connecttothe$dbc=mysqli_connect('localhost','username','password','test'); //Sanctifytheinput...//Theparent_idmustbean$parent_id=}else$parent_id= //Escapethe$task=mysqli_real_escape_string($dbc,strip_tags($_POST['task']));$q="INSERTINTOtasks(parent_id,task)VALUES($parent_id,$r=mysqli_query($dbc,$q);//Reportontheecho'<p>Thetaskhasbeen}elseecho'<p>Thetaskcouldnotbe //Displaytheecho'<formaction="add_task.php"<legend>Adda<p>Task:<inputname="task"type="text"size="60"maxlength="100"<p>ParentTask:<selectname="parent_id"><optionvalue="0">None</option>';//Retrieveall pleted$q='SELECTtask_id,parent_id,taskFROMtasks pleted="0000-00-00?ORDERBYdate_added$r=mysqli_query($dbc,//Alsostorethetasksinanarrayforuse$tasks=//Fetchthewhile(list($task_id,$parent_id,$task)=mysqli_fetch_array($r,{ //Addtothe$tasks[]=array('task_id'=>$task_id,'parent_id'=>$parent_id,'task'=>$task); //Completetheechofunctionparent_sort($x,$y)return($x['parent_id']> usort($tasks,//Displayalltheecho'<h2>CurrentTo-Doforeach($tasksas$task)echo echo該表單有一個(gè)主文本框和一個(gè)下拉菜單,如圖1-11所示。為了檢查表單的提交情況,這個(gè)條件語(yǔ)句查看這個(gè)請(qǐng)求方法是命名為確保parent_id的值是個(gè)整數(shù):?FILTER_VALIDATE_INT,$parent_id?}else$parent_id=

1-11HTML表}這里parent_id的值是另一個(gè)任務(wù)的task_id值。其數(shù)據(jù)來(lái)源于一個(gè)下拉菜單,這意味著它來(lái)確保這里的值是比1大的整數(shù)。如果因?yàn)槟撤N原因,不是這種情況,那么其值將為0。這里提到的過(guò)濾擴(kuò)展在PHP5.2PHP內(nèi)核。如果對(duì)其不甚了解,可以參考PHP手冊(cè)。$task=?myqli_real_escape_tring()函數(shù)會(huì)處理提交的描述任務(wù)的字符串,使其對(duì)于查詢操作來(lái)說(shuō)是安全的。為了防止跨站注入XS),trip_tags()函數(shù)也同時(shí)用于檢查描述任務(wù)的字符串。$q="INSERTINTO?(parent_id,task)if(mysqli_affected_rows($dbc)?1)?}elseecho'<p>Thetaskcouldnot?}}//Endofsubmissionecho'<form?<legend>Adda<p>Task:<input?type="text"??一個(gè)有效值為0,表示不隸屬于其他任何任務(wù)的任務(wù)。?taskFROMtasksWHERE?completed="0000-00-00?ORDERBYdate_added這個(gè)查詢操作返回每個(gè)未完成任務(wù)的三個(gè)信息(一旦一個(gè)任務(wù)已經(jīng)完成,它的date_completed字段將會(huì)被賦予一個(gè)非零值。這里我們只選擇未完成的任務(wù),因?yàn)橄蛞粋€(gè)已經(jīng)完這里的task_id和任務(wù)本身將用在下拉菜單中,parent_id將稍后用于嵌套任務(wù)。$tasks=圖1-12所示。這個(gè)數(shù)組將保存第二個(gè)列表中被使用的任務(wù)。1-12這個(gè)頁(yè)面有兩個(gè)地方包含了任務(wù)列while(list($task_id,?$task)=echo"<option??$task_id,'parent_id'}這個(gè)while1-131-13PHP代碼生成的下拉菜單的HTMLecho?value="AddThisparent_idfunctionparent_sort($x,{return($x['parent_id']?$y[}usort($tasks,這里,parent_id的作用在于區(qū)分務(wù)和子任務(wù),所以PHP foreach($tasksas$task)echo?}echo這個(gè)循環(huán)會(huì)基于parent_id1-1所示列表的第一步。但是從圖1-12中可以看出,列表還沒(méi)有達(dá)到其應(yīng)有的結(jié)構(gòu),把文件保存為add_task.php并放到我們的 如圖1-14所示

1-14針對(duì)一個(gè)存在的任務(wù)添加PHP5“悄悄地”為函數(shù)的參數(shù)增加了類型約束(typehintin)定函數(shù)中的參數(shù)是什么類型的變量。舉例來(lái)說(shuō),下面的代碼表示這個(gè)函數(shù)有一個(gè)唯一的數(shù)組類型的參數(shù)類型限制,但是標(biāo)量類型如字符串和整型除外。正如你將在本書(shū)后面章節(jié)中看到的那樣,類6章中詳細(xì)講解。高級(jí)函數(shù)定PHP程經(jīng)驗(yàn)的程序員,也應(yīng)該已經(jīng)在代碼中創(chuàng)建了很多自定義函數(shù)了。但是在高級(jí)編程領(lǐng)域,自4遞歸靜態(tài)?以方式接收?函遞歸(recursion)就是函數(shù)自functionsomefunction()//Somecode.//Possibleother} functionlist_dir($start)$contents=scandir($start);foreach($contentsas$item){if(is_dir("$start/$item")//Use$item.}else//Use}//Endofif-}//Endof}//Endoffunction.函數(shù)的執(zhí)行操作(最后一行)調(diào)用函數(shù)list_dir('.'),設(shè)定當(dāng)前 作為起點(diǎn)。在該函數(shù)中,scandir()函數(shù)得 的內(nèi)容,然后利用foreach循環(huán)遍歷每一個(gè)條目。如果該條目,函數(shù)將被再次調(diào)用,但是使用新的作為起點(diǎn)參數(shù)。遞歸函數(shù)將在每個(gè)子被在使用遞歸的時(shí)候,需要注意兩件事情。第一個(gè)事情就是,像使用循環(huán)一樣,我們需要確保函數(shù)中有一個(gè)退出(ou)語(yǔ)句:到達(dá)某個(gè)條件,將使函數(shù)終止調(diào)用它自己。在上面的例子中,函數(shù)將在遍歷完子第二件需要注意的事情是,從服務(wù)器資源的角度來(lái)說(shuō),遞歸函數(shù)的成本是比較高的。需要銘記在心的是,每一次函數(shù)調(diào)用都是需要消耗內(nèi)存和處理器的,并且第一次調(diào)用必須等到其他所有調(diào)用都結(jié)束時(shí)才會(huì)結(jié)束。遞歸的層次如果比較深,比如100次遞歸,就有可能使服務(wù)器死機(jī)。簡(jiǎn)單地說(shuō),有時(shí)遞歸是唯一的解決方案,但是通常情況下應(yīng)使用循環(huán)更加高效。在本章開(kāi)頭創(chuàng)建的任務(wù)列表中,獲取和展示所有的任務(wù)項(xiàng)目不是很難(參見(jiàn)圖1-12)。然而,在add_task.php(1.2)中定義的方法并不能完全適合在圖1-1中的嵌套任務(wù)結(jié)構(gòu)。在文本編輯器或者集成開(kāi)發(fā)環(huán)境中新建一個(gè)PHP,并命名為view_tasks.php,并且以下面的HTML代碼開(kāi)始(詳細(xì)代碼見(jiàn)1.3)。<!doctype<html<h2>CurrentTo-Do<?php#Script13-function{global$tasks;echo'<ol>';這個(gè)函數(shù)接收一個(gè)數(shù)組作為參數(shù),在參數(shù)內(nèi)部需要能夠數(shù)組$tasks(主數(shù)組)—我1.3 <!doctype<html<metacharset="utf-<title>View<linkrel="stylesheet"<?php#Script1.3-view_tasks.php/*Thispageshowsallexisting*Arecursivefunctionisusedtoshow*tasksasnestedlists,as//Functionfordisplayinga//Receivesoneargument:anfunction{//Needthemain$tasksglobalecho'<ol>';//Startanorderedlist.//Loopthrougheachforeach($parentas$task_id=>{//Displaytheecho//Checkfor//Callthisfunction echo'</li>';//Completethelistitem. echo'</ol>';//Closetheorderedlist. }//Endofmake_list()function.//Connecttothe$dbc=mysqli_connect('localhost','username','password','test');//Retrieveall pleted$q='SELECTtask_id,parent_id,taskFROMtasks pleted="0000-00-00?ORDERBYparent_id,date_added$r=mysqli_query($dbc,//Initializethestorage$tasks=//Loopthroughthewhile(list($task_id,$parent_id,$task)=mysqli_fetch_array($r,{//Addtothe //For//Sendthefirstarray//tothemake_list() foreach($parentas$task_id?$todo)echoforeach循環(huán)將遍歷整個(gè)數(shù)組,并在<li>中顯示每個(gè)元素if{}這是這個(gè)最重要的部分。從數(shù)據(jù)庫(kù)獲取的任務(wù)列表可能是如圖1-15所示的那樣的一個(gè)數(shù)組。對(duì)于主數(shù)組來(lái)說(shuō),關(guān)鍵字是parent_id,而元素是位于這個(gè)parent_id之下的任務(wù)集合。因此,在打印出了初始的<li>和任

圖1-15這段PHP (或者,這個(gè)任務(wù)是不是一個(gè)父任務(wù)元素?)。換句話說(shuō),在$tasks里是否有元素的關(guān)鍵字的值是這個(gè)任務(wù)的ID?如果有,當(dāng)前任務(wù)就有子任務(wù),因此這個(gè)函數(shù)需要被再次調(diào)用,以數(shù)組的這一部分(關(guān)鍵字的值是這個(gè)task_id,其值是子任務(wù)數(shù)組的元素)作為參數(shù)。foreachecho}//EndofFOREACHloop.echo'</ol>';}//Endofmake_list()$dbc=中,然后調(diào)用一次make_list()函數(shù)。?taskFROMtasksWHERE?completed="0000-00-00?ORDERBYparent_id,?這個(gè)查詢獲取每個(gè)任務(wù)項(xiàng)的3個(gè)信息:ID、parent_id以及任務(wù)的內(nèi)容。其中的條件表示只選擇未完成的任務(wù)。得到的結(jié)果以parent_id進(jìn)行排序,所以頂級(jí)任務(wù)(parent_id為0的任務(wù))會(huì)首先返回。次要排序參數(shù)是date_added,可以讓任務(wù)按照其被添加的次序返回(假定$tasks=while(list($task_id,?$task)=$tasks[$parent_id][$task_id]?}這里的$tasks數(shù)組將保存二維數(shù)組中的每一項(xiàng)任務(wù),如圖1-15所示。正如在第4步中介紹的那樣,數(shù)組最外層的關(guān)鍵字是來(lái)自數(shù)據(jù)表的parent_id的值,而最外層數(shù)據(jù)的元素是具有相應(yīng)的parent_id值的任務(wù)。?在處理數(shù)組時(shí),知道和理解相應(yīng)的結(jié)構(gòu)是至關(guān)重要的。如果取消這一行的注釋去1-15make_lit雖然變量$tasks是個(gè)數(shù)組,但是make_list()函數(shù)只需要被調(diào)用一次,并把第一個(gè)數(shù)組元素傳遞給它。這個(gè)元素的值是一個(gè)由parent_id為0的任務(wù)組成的數(shù)組。在這個(gè)函數(shù)中,保存文件為view_tasks.php并放到 中,然后在瀏覽器中測(cè)試,如圖1-

使用add_task.php來(lái)添加的子任務(wù),重新在瀏覽器中測(cè)試該,如圖1-圖1-16任務(wù)頁(yè)面,以嵌套形式顯示任務(wù)列 圖1- make_list()$tasks在使用遞歸函數(shù)時(shí) 事實(shí)上,在使用任何可能會(huì)被多次調(diào)用的函數(shù)時(shí),我們都應(yīng)考慮使用靜態(tài)變量。靜態(tài)變量讓函數(shù)在多次被調(diào)用時(shí)記住變量的值,而這些變量并不是全局變量。舉例來(lái)說(shuō),make_lit()函數(shù)可以重寫一,完整的任務(wù)列表作為其第二個(gè)參數(shù)并且為可選參數(shù),賦給一個(gè)靜態(tài)本地變量static$tasks=}make_list($tasks[0],1-17中,顯示被比較的數(shù)值并不難,但是統(tǒng)計(jì)遞歸的次數(shù)就需要使用靜態(tài)變量了。為了演示這種用法,sort.php將按照下面的步驟進(jìn)行修改。像下面這樣來(lái)修改name_sort()函數(shù)(詳見(jiàn)1.4):functionname_sort($x,{static$count=?return?}1.4 <!doctype<html<metacharset="utf-<title>SortingMultidimensional<linkrel="stylesheet"<?php#Script1.4-sort2.php/*Thispagecreatesamultidimensional*ofnamesand*Thearrayisthensorted*oncebynameandonceby*Astaticvariablehasbeenaddedto*functionstoseehowmanytimestheyare//Createthe//Array//studentID=>array('name'=>'Name','grade'=>$students= 256=>array('name'=>'Jon','grade'=> 2=>array('name'=>'Vance','grade'=>9=>array('name'=>'Stephen','grade'=>364=>array('name'=>'Steve','grade'=>68=>array('name'=>'Rob','grade'=> //Namesortingfunctionname_sort($x,$y)//Showiterationsusingastaticstatic$count=echo"<p>Iteration$count:{$x['name']}vs.returnstrcasecmp($x['name'], //Gradesorting//SortinDESCENDING//Showiterationsusingastaticstatic$count=echo"<p>Iteration$count:{$x['grade']}vs.return($x['grade']< uasort($students,echo'<h2>ArraySortedByName</h2><pre>'.print_r($students,1).'</pre>';//Sortbyuasort($students,echo'<h2>ArraySortedByGrade</h2><pre>'.print_r($students,1).'</pre>'; 這個(gè)函數(shù)里添加了3行代碼,第一行了一個(gè)靜態(tài)變量,名稱為$count。它的初始值為1,但是這個(gè)賦值操作只在函數(shù)第一次被調(diào)用時(shí)執(zhí)行(因?yàn)樗且粋€(gè)靜態(tài)變量。然后下一的值。最后,變量$count的值被增加1。functiongrade_sort($x,{static$count=??}這里為grade_sort()函數(shù)添加的3行代碼和添加在name_sort()函數(shù)中的是一樣的,只是其中用于比較的關(guān)鍵字是grade而不是name。保存文件,并命名為sort2.php,放在Web 圖1-18所示。(同時(shí)我也移除了打印數(shù)組原始結(jié)構(gòu)的那行代碼)為$students數(shù)組增加一些額外的元素,然后再次運(yùn)行,結(jié)果如圖1-19所示圖1-18對(duì)原始的5元素?cái)?shù)組按照進(jìn) 圖1-19向主數(shù)組增加3個(gè)元后,根排序需要調(diào)用6次排序函 名字的排序需要20次遞歸調(diào)1.2.3函本部分要討論最后一個(gè)高級(jí)話題:函數(shù)(anonymousfunction,亦稱lambda)的使用。簡(jiǎn)單地說(shuō),一個(gè)函數(shù)就是一個(gè)沒(méi)有名字的函數(shù)。創(chuàng)建函數(shù)的特性是在PHP5.354創(chuàng)建一個(gè)函數(shù)的方式和我們創(chuàng)建其他函數(shù)沒(méi)有什么不同,只是,它沒(méi)有一個(gè)名字。然而,為了方便之后這個(gè)函數(shù)例如該,這個(gè)函數(shù)的定義需要賦值給個(gè)變量。 o={echo 看上去這種做法有些不太容易理解,但是前提其實(shí)很簡(jiǎn)單:就像賦值給一個(gè)字符串或者整數(shù)類型的變量一樣,我們只是給一個(gè)函數(shù)定義賦值。由于這個(gè)原因,在賦值語(yǔ)句結(jié)束時(shí)需粗略來(lái)說(shuō)為了調(diào)用函數(shù)(當(dāng)然在其被定義好了之圖1-20所示。圖1-20通過(guò)變量調(diào) 這種使用函數(shù)的特殊方式有其優(yōu)勢(shì)所在,但是也有一種更加明顯和簡(jiǎn)單的方式來(lái)使用函數(shù),我們需要討論一下。PHP中一些函數(shù)可以使用另一個(gè)函數(shù)作為其參數(shù),舉例來(lái)說(shuō),array_map()函數(shù)接收一個(gè)函數(shù)作為其第一個(gè)參數(shù),第二個(gè)參數(shù)是個(gè)數(shù)組,數(shù)組內(nèi)的每個(gè)functionformat_names($value)//Dowhateverwith}array_map('format_names', 函數(shù),你可以在函數(shù)參數(shù)內(nèi)定義一個(gè)函數(shù)array_map(function($value)//Dowhateverwith},?由于函數(shù)是被直接使用的,因 只需要函數(shù)的定義就可以了 的時(shí)候。在接下來(lái)的步驟中,最后更新一次sort.php的代碼來(lái)使 函數(shù)。注意PHP5.3刪除當(dāng)前對(duì)函數(shù)name_sort()和grade_sort()的定義代碼(1.5)。修改第一次對(duì)uasort()函數(shù)的調(diào)用,這里使用函數(shù)的方式uasort($students,function($x,$y)return?修改第二次對(duì)uasort()函數(shù)的調(diào)用,這里使用函數(shù)的方式uasort($students?保存文件為sort3.php,放到Web 121PHP5.3之前的版本,我們也可以使用create_function()函數(shù)來(lái)創(chuàng)建和函數(shù)類似的函數(shù)。

1-21最終結(jié)果沒(méi)有因?yàn)槭褂煤瘮?shù)可以用做閉包,一個(gè)公認(rèn)的高級(jí)概念。閉包在PHPJavaScript1.5 <!doctype<html<metacharset="utf-<title>SortingMultidimensional<linkrel="stylesheet"<?php#Script1.5-sort3.php/*Thispagecreatesamultidimensional*ofnamesand*Thearrayisthensorted*oncebynameandonceby*Thisversionusesanonymous//Createthe//Array//studentID=>array('name'=>'Name','grade'=>$students= 256=>array('name'=>'Jon','grade'=> 2=>array('name'=>'Vance','grade'=>9=>array('name'=>'Stephen','grade'=>364=>array('name'=>'Steve','grade'=>68=>array('name'=>'Rob','grade'=> uasort($students,function($x,$y)returnstrcasecmp($x['name'],32 echo'<h2>ArraySortedByName</h2><pre>'.print_r($students,1).'</pre>';//Sortbyuasort($students,function($x,$y)return($x['grade']<38 echo'<h2>ArraySortedByGrade</h2><pre>'.print_r($students,1).'</pre>'; 變量本身。也就是說(shuō),函數(shù)使用的其實(shí)是變量的一個(gè)副本。這種行為的結(jié)果就是在該函數(shù)內(nèi)functionincrement($var)}$num=2;echo$num;//Still取代這種默認(rèn)行為的一個(gè)方法是,將這個(gè)函數(shù)的參數(shù)傳遞方式設(shè)置為按照傳遞,而的值,而不需要使用全局變量。第二個(gè)好處是關(guān)于性能方面的。在需要傳遞的數(shù)據(jù)比較大的場(chǎng)景按傳意著PHP不需要去構(gòu)建一份數(shù)的副本。對(duì)于字符串或數(shù)字來(lái)說(shuō),PHP不需要functionincrement(&$var)}$num=2;echo$num;//或 functionincrement($var)}$num=2;echo$num;//3原型文檔語(yǔ)原型文檔(heredo)是一種封裝字符串的替代方式,它不像標(biāo)準(zhǔn)的單引號(hào)或者雙引號(hào)那樣使用頻繁,但是其具有相同的功能。使用原型文檔就像是把花生和黃油抹在香蕉上一樣:原型文檔的工作方式和雙引號(hào)一樣,它包裹的內(nèi)容將被打印出來(lái),但是它還允許我們自己定義分界符。在要打印出大量的TL代碼包自身的雙引)的時(shí)候,原型文原型文檔以<<<開(kāi)始,后面緊跟著分界符。分界符通常需要是全部大寫的單詞,它只能在字符串的末尾使用相同的分界符,但是這次沒(méi)有符號(hào)<<<。結(jié)束分界符必須位于單獨(dú)1-22$var=echo<<<EOTSomevar$varThisvar$that$string=<<<EODstringwith$var\necho圖1-22從結(jié)果中可以看出,使用原型文檔語(yǔ)法的結(jié)果和使引號(hào)的完全一使用ED和ET作為分界符是比較常見(jiàn)的方式(它們一般不會(huì)出現(xiàn)在字符串中,但是這并不是必須的。原型文檔的語(yǔ)法是個(gè)不錯(cuò)的選擇,但是,說(shuō)得更透徹些,它又是十分特殊的。如果語(yǔ)法不是百分之百準(zhǔn)確無(wú)誤,甚至只為了展示原型文檔的使用,我們來(lái)重寫文件view_tasks.php,讓用戶可以對(duì)任務(wù)進(jìn)行標(biāo)記,如圖1-23所示。在文本編輯器或者集成開(kāi)發(fā)環(huán)境中打開(kāi)文件view_tasks.php(1.3)。make_list(函數(shù)中,把打印任務(wù)的相關(guān)語(yǔ)句修改為(如1.6所示):

1-23查看任務(wù)列表的頁(yè)面現(xiàn)在多了復(fù)選框,echo?1.6 最初的view_tasks.php代碼(1.3)修改為一個(gè)表單,讓用戶可以對(duì)任務(wù)進(jìn)行標(biāo)記,這里使用原型文檔來(lái)創(chuàng)建一些HTML標(biāo)記<!doctype<html<metacharset="utf-<title>View<linkrel="stylesheet"<?php#Script1.6-view_tasks2.php/*Thispageshowsallexisting*Arecursivefunctionisusedtoshow*tasksasnestedlists,as*Taskscannowbemarkedas//Functionfordisplayinga//Receivesoneargument:anfunctionmake_list($parent)globalecho'<ol>';//Startanorderedforeach($parentas$task_id=>{//Startwithaecho<li><inputtype="checkbox"name="tasks[$task_id]"value="done">//Checkfor echo'</li>';//Completethelist}//EndofFOREACHecho'</ol>';//Closetheordered}//Endofmake_list()function.//Connecttothe$dbc=mysqli_connect('localhost','username','password','test');if(($_SERVER['REQUEST_METHOD']==&&&&&&!empty($_POST['tasks']))//Definethe$q='UPDATEtaskspleted=NOW()WHEREtask_idIN//Addeachtaskforeach($_POST['tasks']as$task_id=>$v) $q.=$task_id.', //Completethequeryand$q=substr($q,0,-2).$r=mysqli_query($dbc,//Reportontheif(mysqli_affected_rows($dbc)==count($_POST['tasks']))echo'<p>Thetask(s)havebeenmarkedas}elseecho'<p>Notalltaskscouldbemarkedas 67}//Endofsubmission//Retrieveall pleted$q='SELECTtask_id,parent_id,taskFROMtasks pleted="0000-00-00?ORDERBYparent_id,date_added$r=mysqli_query($dbc,$tasks=while(list($task_id,$parent_id,$task)=mysqli_fetch_array($r,MYSQLI_NUM))$tasks[$parent_id][$task_id]= //Makeaecho<p>Checktheboxnexttoataskandclick"Update"tomarkataskas?(it,andanysubtasks,willnolongerappearinthis<formaction="view_tasks2.php" //Completetheecho<inputname="submit"type="submit"value="Update" echo"<li><input??echo'<li><input?name="tasks['. ?&&isset($_POST['tasks'])只有在表單提交,$_POST[taks']有一個(gè)值,并且是一個(gè)非空的數(shù)組的時(shí)候,數(shù)據(jù)庫(kù)才會(huì)被更新使任務(wù)標(biāo)記為已完成。哪怕只有一個(gè)復(fù)選框被選中,$_POST[tasks']也會(huì)是一個(gè)數(shù)組。$q='UPDATEtasksSET?IN?$task_id=>$v)$q.=$task_id.',}$q=substr($q,0,-2).UPDATEtasks ?NOW()WHEREtask_idIN(X,Y, pleted字段設(shè)置為當(dāng)前日期和時(shí)間,這樣它就不會(huì)顯 pleted為空的任務(wù)條目。if?==count($_POST['tasks'])){?markedas}elseecho'<p>Notalltasks?bemarkedas}}//Endofsubmission在調(diào)用make_list()函數(shù)之前,先添加初始表單echo<p>Checktheboxnexttoa?andclick"Update"tomark?taskascompleted(it,and?subtasks,willnolonger?inthis<form由于make_list()函數(shù)的執(zhí)行效果,因此,只要父任務(wù)被標(biāo)記為已經(jīng)完成,子任務(wù)就不會(huì)在調(diào)用make_list()函數(shù)之后結(jié)束表單。echo把文件保存為view_tasks2.php,放在Web 目選中,標(biāo)記為已完成,如圖1-23所示,然后提交表單,如圖1-24所示。1-24更新之后的任務(wù)列知識(shí)拓展:nowdocPHP5.3nowdoc語(yǔ)法。nowdoc相對(duì)于原型文檔正如單引號(hào)對(duì)于雙引號(hào)一樣。也就是說(shuō),nowdoc提供了另外一種封裝字符串的方法,但是在nowdoc里的任何變量不會(huì)被從語(yǔ)法上來(lái)說(shuō),nowdoc遵循和原型文檔一樣的規(guī)則,唯一的區(qū)別在于,nowdoc中的分$var=stringwith$var澄清一下,$string$ver23printf()對(duì)于大多數(shù)PHP程序員來(lái)說(shuō),只需要使用print()和echo()這兩個(gè)函數(shù)來(lái)顯示文本和變量就足夠了。但是高級(jí)程序員則偶爾會(huì)使用更為復(fù)雜的printf()函數(shù),這個(gè)函數(shù)不僅能顯示文本,還可以設(shè)置輸出的格式。PHP手冊(cè)中對(duì)這個(gè)函數(shù)的定義如下:printf(stringformat[,?format是由直接文本變量和特殊格式參數(shù)組成的字符串。特殊格式參數(shù)由百分?符號(hào)說(shuō)明符(+/–)可以強(qiáng)制?填充說(shuō)明符表示用于右填充的字符(空格是默認(rèn)的,但是對(duì)于數(shù)字來(lái)說(shuō)可能需要使用0)。?對(duì)齊說(shuō)明符(默認(rèn)是右對(duì)齊的,使用減號(hào)(–)可以實(shí)現(xiàn)左對(duì)齊?一個(gè)數(shù)字,用于表示要占用的最小寬度。?精度說(shuō)明符,表示浮點(diǎn)數(shù)應(yīng)該顯示小數(shù)點(diǎn)后的多少位(或者字符串里的多少個(gè)字符?類型說(shuō)明符,見(jiàn)表1-11-1類型說(shuō)明字含字含b二進(jìn)制f浮點(diǎn)c依照ASCII值的字o八進(jìn)制d帶符號(hào)十進(jìn)制整s字符e科學(xué)x十六進(jìn)制u無(wú)符號(hào)十進(jìn)制這些看起來(lái)似乎挺復(fù)雜的,但是也確實(shí)如此。我們可以從數(shù)字開(kāi)始練習(xí)使用它,如圖1-25所示。printf('b:%b<br>c:%c?%d<br>f:%f,80,80,80,這是同一個(gè)數(shù)字的4種不同的表示方式。第一個(gè)格式把80顯示為二進(jìn)制數(shù)字,第二個(gè)格式顯示80對(duì)應(yīng)的ASCII字符(也就是大寫的P),第三個(gè)格式是個(gè)整型數(shù),第四個(gè)格式是在此基礎(chǔ)上,從中選擇兩種最常用的數(shù)字類型—d和f,然后再增加一些其他格式,如圖1-26所示。printf('%0.2f<br>%+d<br>%02f?8,8,圖1-25使用四種不同的類型說(shuō)明符

1-26使用printf函數(shù)設(shè)置數(shù)字的首 數(shù)字8以浮點(diǎn)數(shù)表示,小數(shù)點(diǎn)后面有兩位小數(shù),不足的位數(shù)以0填充。然后,81235.456顯示為具有兩位小數(shù)的浮點(diǎn)數(shù)(結(jié)果中展示printf('Thecostof%d%sat$%0?sprintf()printf幾乎完全一樣,但是它不是顯示格式化的字符串,而

1-27混合打印出數(shù)字和字符在文本編輯器或者集成開(kāi)發(fā)環(huán)境中打開(kāi)add_task.php(1.2)。刪除對(duì)函數(shù)mysqli_real_escape_string()的調(diào)用(如1.7所示 定義INSERT語(yǔ)句的那行代碼做如下修改:$q=sprintf(INSERTINTO?(parent_id,task)??當(dāng)我們使用printf()SL命令和變量的方式來(lái)創(chuàng)建查詢語(yǔ)句了。盡管這里的例子中開(kāi)始的代碼也不算太難看,但是對(duì)于更加復(fù)雜的查詢語(yǔ)來(lái)照寫能”會(huì)包很多$var[index']}這樣的東西,而且還很容易產(chǎn)生錯(cuò)誤,不方便調(diào)試。使用sprintf()函數(shù)的方法可以有效地把查詢和要使用的數(shù)據(jù)分離,同時(shí)還能夠集成函數(shù)1.7對(duì)add_task.php頁(yè)面做些小的修改(如1.1所示),展示另一種簡(jiǎn)潔的創(chuàng)建<!doctype<html<metacharset="utf-<title>Adda<linkrel="stylesheet"<?php#Script1.7-add_task2.php/*Thispageaddstaskstothetasks* $dbc=mysqli_connect('localhost','username','password','test');$parent_id=}else$parent_id= ?mysqli_real_escape_string($dbc,$r=mysqli_query($dbc,$q); echo'<p>Thetaskhasbeen }else echo'<p>Thetaskcouldnotbe //Displaytheecho'<formaction="add_task2.php"<legend>Adda<p>Task:<inputname="task"type="text"size="60"<p>ParentTask:<selectname="parent_id"><option$q='SELECTtask_id,parent_id,taskFROMtasks pleted="0000-00-00?ORDERBYdate_added$r=mysqli_query($dbc,$tasks=while(list($task_id,$parent_id,$task)=mysqli_fetch_array($r,MYSQLI_NUM))echo"<option$tasks[]=array('task_id'=>$task_id,'parent_id'=>$parent_id,'task'=> echo把表單的actionadd_task2.phpvie_task.php頁(yè)面)都能夠以更好的方式顯示任務(wù)列表,所以沒(méi)有必要在這里包含這些代碼。保存文件為add_task2.php,將其放在中,在瀏覽器中進(jìn)試,如圖1-28所示

1-28頁(yè)面的運(yùn)行情況和之前沒(méi)有區(qū)printf('Thetaxrateis?vprintf()與printf()從格式參數(shù)上來(lái)說(shuō),sscanf()和fscanf()函數(shù)分別等同于printf()和sprintf()scanf()函數(shù)用于輸入,而fscanf()用于從文件數(shù)據(jù)1.5回顧和啟示◆回顧和啟在本書(shū)的新版中,每一章將以一個(gè)“回顧和啟示”小節(jié)結(jié)束。在這些小節(jié)中,看到關(guān)于本章中討論過(guò)的知識(shí)材料相關(guān)的一些問(wèn)題,還會(huì)提示讀者如何通過(guò)去擴(kuò)展自己的如果你對(duì)本章有任何問(wèn)題,可以本書(shū)的支持 /forums/)使用什么函數(shù)去按值對(duì)一個(gè)數(shù)組進(jìn)行排序?如果排序中要保留關(guān)鍵字呢?如何按關(guān)鍵字對(duì)數(shù)組進(jìn)行排序?什么是函數(shù)?在PHP的哪個(gè)版本中引入了函數(shù)使用原型語(yǔ)法有哪些規(guī)則要遵循?和其他的替代方案相比,原型文檔的方式有什么優(yōu)勢(shì)?printf()和sprintf()1)sort.php,使用自定義函數(shù)的方式更優(yōu)雅地產(chǎn)生出結(jié)果。2)完成add_task.php文件,使其包含合適的錯(cuò)誤處理。 使用本章中提供的建議之一,比如通過(guò)傳遞參數(shù),或者使用靜態(tài)變量,更()如果你好奇,可以在網(wǎng)上搜索一些PHP中使用函數(shù)的例子view_tasks.php,使其可以顯示已經(jīng)完成的和將要完成的任務(wù)列表,并以不在view_tasks.php文件中增加一個(gè),在URL中傳遞一個(gè)參數(shù),用于標(biāo)示是所有任務(wù)都需要顯示出來(lái),還是只顯示未完成的任務(wù)。根據(jù)傳入的參數(shù)值修改SQL查詢語(yǔ)句。修改文件尋找關(guān)于printf()和sprintf()函數(shù)的其他用法。提示:查看PHP手冊(cè)中關(guān)于這些函2WebPHP程序員的職業(yè)生涯通常是從專門完成一個(gè)特定功能的獨(dú)立的開(kāi)始的。然后再逐漸使用越來(lái)越多的文件來(lái)建立Web應(yīng)用程序,最后可能會(huì)在自己的服務(wù)器上開(kāi)發(fā)站點(diǎn)。如果幸運(yùn)的話,還可能會(huì)讓站點(diǎn)使用多臺(tái)不同的服務(wù)器。無(wú)論的項(xiàng)目有多大,在PHP程序員的日常工作中,學(xué)習(xí)開(kāi)發(fā)Web應(yīng)用程序的新的和改進(jìn)的方式都是重要的組成部分。本章中,著重介紹初中級(jí)以上的Web應(yīng)用程序的開(kāi)發(fā)。從解釋如何模塊化一個(gè)開(kāi)始。然后學(xué)到一些關(guān)于ApacheWeb服務(wù)器的知識(shí),包括使用它的mod_rewrite特性,用來(lái)生成對(duì)搜索引擎優(yōu)化(SEO)規(guī)則友好的地址(URL)。以筆者的經(jīng)驗(yàn)來(lái)說(shuō),程序員的成長(zhǎng)是從編寫完成比較單能的單個(gè)頁(yè)面程序開(kāi)始的。一段時(shí)間之后,工作內(nèi)容將會(huì)變?yōu)殚_(kāi)發(fā)含有多個(gè)頁(yè)面的,并且包括模板以及狀態(tài)管理。在不斷累一經(jīng)驗(yàn)后,PHP程序員開(kāi)始利用較少的頁(yè)面來(lái)完成和多面同樣多的工作。比如可以讓同一個(gè)既顯示表單同時(shí)又處理表單,不再使用兩個(gè)獨(dú)立的文件?;蛘撸∠?,高級(jí)PHP程序員開(kāi)始編寫一系列具單能的程序,它們分別完成特定工作這最式正對(duì)eb站點(diǎn)行塊化設(shè)計(jì)的前提。這里舉例說(shuō)明模塊化一個(gè)站點(diǎn)的方式。創(chuàng)建一個(gè)偽Web站點(diǎn)(也就是說(shuō),組成部分進(jìn)行分解、組織以及合成到一起。取代使用不同的單獨(dú)頁(yè)面的方式(比如contact.php、由于這個(gè)應(yīng)用程序沒(méi)有使用數(shù)據(jù)庫(kù),因此這里我們沒(méi)有為其創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)配置文件。如果需要使用數(shù)據(jù)庫(kù),我們可以編寫創(chuàng)建數(shù)據(jù)庫(kù)連接的文件,命名為myql.inc.php或者potgresql.incphp、db.incphp這個(gè)文件應(yīng)該可以保存在 下,但是最好保存在 con?g.inc.phpDB,用于指定這個(gè)文件在服務(wù)器上的絕對(duì)路徑。 我們開(kāi)發(fā)的每個(gè)Web程序都會(huì)由配置文件開(kāi)始。配置文件可以有很多作用。最重要的定義??管理從根本上說(shuō),站點(diǎn)內(nèi)的每個(gè)頁(yè)面都有可能需要的信息就應(yīng)該保存在配置文件中。(這里順便提一下,對(duì)于不是大部分頁(yè)面都需要的函數(shù),把它放在單獨(dú)的文件里,從在21在21<?php#Script2.1-2.1 配置文件是關(guān)鍵的,它定義了范圍內(nèi)的常數(shù),并且指明了如何1<?php#Script2.1-234*Filename:5*Createdby:LarryE.6*Contact:,7*Lastmodified:June5,8**Configurationfiledoesthefollowing*-Hassitesettingsinone*-StoresURLsandURIsas*-Setshowerrorswillbe #*****SETTINGS*****// ed ='a //Determinewhetherwe'reworkingonalocal//oronthereal}else //DeterminelocationoffilesandtheURLofthe//Allowfordevelopmentondifferent{//Alwaysdebugwhenrunning$debug=TRUE;//Definethe }{ *Mostimportant*The$debugvariableisusedtoseterror if($p=='thismodule')$debug= *Todebugtheentiresite,do $debug= *beforethisnext //Assumedebuggingis $debug= #*****SETTINGS***** #**************************** #*****ERRORMANAGEMENT***** //Createtheerror functionmy_error_handler($e_number,$e_message,$e_file,$e_line,{ global$debug,$contact_; //Buildtheerror $message="Anerroroccurredinscript'$e_file'online$e_line:$e_message"; //Append$e_varstothe $message.=print_r($e_vars, if($debug){//Showtheerror. echo'<divclass="error">'.$message. }{ error_log($message,1,$contact_);//Send. //Onlyprintanerrormessageiftheerrorisn'tanoticeor if(($e_number!=E_NOTICE)&&($e_number<2048)) echo'<divclass="error">Asystemerroroccurred.Weapologizefor? 105}//Endofmy_error_handler()definition.//Usemyerror#*****ERRORMANAGEMENT*****#*****************************Filename:*Createdby:LarryE.*Contact: ?*Lastmodified:June5,**Configurationfildoes?following*-Hassitesettingsin?*-StoresURLsandURIs?*-Setshowerrorswill?由于配置文件是比較通用的文件,因此它應(yīng)該是程序里注釋最好的。 ? 對(duì)于實(shí)際運(yùn)行的站點(diǎn)來(lái)說(shuō),我比較傾向于用戶在發(fā)現(xiàn)錯(cuò)誤時(shí)能夠通過(guò)電子郵件的方式通知到我,因此我了一個(gè)變量,為每個(gè)通用的交流信息保存一個(gè)“發(fā)送到”的電子郵件地址。這個(gè)地址可以是的郵箱,但是一旦開(kāi)發(fā)的站點(diǎn)實(shí)際運(yùn)行了,這就應(yīng)該是站點(diǎn)管理員的電子郵箱地址。$host=$local=}else$local=}我通常都會(huì)在本地服務(wù)器開(kāi)發(fā),然后把完整的代碼上傳到實(shí)際的服務(wù)器。這兩種環(huán)境具有各自特定的設(shè)置。在理想情況下,配置文件應(yīng)該可以根據(jù)所處的服務(wù)器環(huán)境自動(dòng)為了測(cè)試站點(diǎn)是否運(yùn)行于本地環(huán)境,我們首先檢查一下變量的前?單詞local(在中用到?IP地址的開(kāi)始,192.1或者127.0,兩種情況都說(shuō)明條件是否滿足,$local變量將會(huì)被賦予一個(gè)布爾值(真或者假),以便在后面的中使用。if($local)$debug=?'/path/to/html/folder/');?'?}{?? ?}我經(jīng)常在自己的Web應(yīng)用程序中使用3個(gè)常量。其中,常量BASE_URI在服務(wù)器上的絕對(duì)路徑。這個(gè)常量可以在中包含一個(gè)文件的時(shí)候很方便地使用絕對(duì)路徑來(lái)文件。如果你正在使用indows中的XAMPP開(kāi)發(fā)環(huán)境,這個(gè)值就有可能是這樣的:xampphtdocs\ch02。常量BASE_URL是主機(jī)名和 是。最后,常量DB是包含數(shù)據(jù)庫(kù)連接信息的文件的絕對(duì)路徑。出于安全方面的考慮,這個(gè)常量最好保存在Web 可以注意到每一個(gè)常量在不同的環(huán)境下有不同的設(shè)置:一種是在測(cè)試服務(wù)器,另一種是在正式的線上服務(wù)器。如果是在測(cè)試服務(wù)器上($localTRUE),我同時(shí)還會(huì)打開(kāi)$debug=}我們還使用了變量$debug$debug的值會(huì)為TRUE $debug=function?($e_number,?$e_file,$e_line,{global P允許我們定義自己的錯(cuò)誤處理函數(shù),來(lái)取代使用內(nèi)置的處理機(jī)制。關(guān)于這個(gè)過(guò)程或者語(yǔ)的信息可以考P手冊(cè)者我一本書(shū)《PndyLorWebte:ialuckartudebook(acpte,2012)。$message="Anerroroccurred$message.=print_r($e_vars,出于調(diào)試的目的,錯(cuò)誤消息中應(yīng)該盡可能多地包含信息。首先,它應(yīng)該發(fā)生錯(cuò)誤的文件名以及行號(hào)。然后加上每個(gè)已經(jīng)存在的變量的值。這可能會(huì)是大量的數(shù)據(jù),如圖2-1所2-1當(dāng)調(diào)試站點(diǎn)時(shí)錯(cuò)誤消息的顯if($debug){//Showtheerror.echo<divclass="error">'.?$message 如圖2-1在開(kāi)發(fā)一個(gè)站點(diǎn)的時(shí)候是非常有用的,但是對(duì)實(shí)際運(yùn)行的站點(diǎn)來(lái)說(shuō),可能算是一個(gè)巨大的安全。這段代碼將把這些信息顯示在一個(gè)DIV中,這個(gè)有個(gè)類名為error,通過(guò)SS的設(shè)計(jì)也就說(shuō),以創(chuàng)一個(gè)殊的DIV或者不用它。}else? if(($e_number!=E_NOTICE)?($e_number<2048)){?Asystemerror?Weapologizefortheinconvnince}}//Endof$debug對(duì)于線上運(yùn)行的站點(diǎn)來(lái)說(shuō),不應(yīng)該顯示錯(cuò)誤的詳細(xì)信息除非出于調(diào)試的目的暫時(shí)啟動(dòng)相應(yīng)頁(yè)面的調(diào)試模式,而是應(yīng)該通過(guò)郵件的方式發(fā)送錯(cuò)誤消息到設(shè)置的郵箱。函數(shù)error_log()的第二個(gè)參數(shù)為1時(shí)就能完成這種操作。但是對(duì)于用戶來(lái)說(shuō),需要知道站點(diǎn)出現(xiàn)了問(wèn)題,因此站點(diǎn)會(huì)顯示一個(gè)通用的錯(cuò)誤提示消息,如圖2-2所示。如果錯(cuò)誤是個(gè)通知級(jí)別的錯(cuò)誤,或者嚴(yán)格性錯(cuò)誤值為2048,不應(yīng)該有任何信息打印出來(lái)。因?yàn)檫@種錯(cuò)誤一般不會(huì)影響頁(yè)面的操作。2-2在實(shí)際運(yùn)行的站點(diǎn)上,錯(cuò)誤消息的處理方式更加謹(jǐn)慎(和安全}//Endof?definition.?保存文件為con?g.inc.php,并放置在你的Web 下(在一個(gè)叫做includes的子圖2-3顯示了這個(gè) 結(jié)構(gòu)。注意到這里我沒(méi)有使用一個(gè)PHP的關(guān)閉(closingPHPtag)。這在PHP內(nèi)是可以接受的并且對(duì)于這種會(huì)被其他包含的文件來(lái)說(shuō),圖2-3根 (images)、包含文件(includes)以及模塊(modules)等將被用到像你的代碼結(jié)構(gòu)或者文檔一樣,在開(kāi)發(fā)大型的Web應(yīng)用程序的時(shí)候,另外一個(gè)比較重要拆分成同的面和 。主eb檔 ,我之為html,我們應(yīng)有一個(gè)子目錄至,乎有會(huì)么、一個(gè)保存類的 如使了對(duì)編的、一個(gè)函數(shù) 等。更進(jìn)一,為了安全起見(jiàn)我比較傾于你去使用一個(gè)個(gè)性化名字來(lái)命名些文件夾。對(duì)有用戶來(lái)說(shuō),任何時(shí)候都不知道文件和文檔的名字,總是一件好事情。如果你對(duì)站點(diǎn)的管理模塊使用的名字為admin,從安全的角度來(lái)說(shuō),這樣不會(huì)給你帶來(lái)任何好處。TL以使用Smarty(.net)或者其他的模板系統(tǒng),但是我還是比較喜歡只使用兩個(gè)簡(jiǎn)單的文件:一個(gè)頁(yè)頭文件包含頁(yè)面特定的內(nèi)容之前的全部?jī)?nèi)容,一個(gè)頁(yè)腳文件包含頁(yè)面對(duì)于這個(gè)模板,使用HTML5WebTemplates(wwwhtml5webtemplates.co.uk)設(shè)計(jì)的HTML為了給Web站點(diǎn)創(chuàng)建一個(gè)模板,要獨(dú)立于所有的PHP代碼設(shè)計(jì)一個(gè)像標(biāo)準(zhǔn)的HTML頁(yè)面一樣的布局。對(duì)于這里的例子來(lái)說(shuō),正如前面提到的,使用ColourBlue設(shè)計(jì)模板,如圖2-4所示。注意為了節(jié)省本書(shū)篇幅,本例中使用的CSS文件(用于控制布局的)沒(méi)有包含在本書(shū)里,讀者可以從本書(shū)的支持( <!DOCTYPE<div這里第一個(gè)文件將包括原始的HTML(從DOCTYPE到頭部標(biāo)記再到頁(yè)面主體的開(kāi)始。它還包含形成瀏覽器頂部欄和右側(cè)邊欄的代碼,如圖2-4所示。書(shū)中在此將跳過(guò)大量的HTML代碼。完整的代碼請(qǐng)參見(jiàn)2.2或者直接從本書(shū)的支持站點(diǎn)。2-4本站將為所有的頁(yè)面使用的模<title><?phpecho?我們希望頁(yè)面的標(biāo)題(出現(xiàn)在Web24colour_blue)能夠在逐頁(yè)的基礎(chǔ)上產(chǎn)生變化。為此,里使用一個(gè)變量來(lái)表示標(biāo)題,它將通過(guò)PHP輸出。2.2 HTML模板的開(kāi)始。它包含CSSPHP變//ThispagebeginstheHTMLheaderforthesite.//Checkfora$page_titleif(!isset($page_title))$page_title='DefaultPage?><!DOCTYPE8<title><?phpecho$page_title;<linkrel="stylesheet"type="text/css"href="style/style.css"title="style"<div<div<div<div<h2>Simple.Contemporary.Website<div <ul <li><a<li><a<li><a<li><a<li><a <div<div<h3>Latest<h4>NewWebsite<h5>January1st,<p>2010seestheredesignofourwebsite.Takealookaroundandletusknowwhat?think.<br/><ahref="#">Read<h3>Useful <li><ahref="#">link <li><ahref="#">link <formmethod="get"action="index.php" <inputtype="hidden"name="p"value="search"<inputclass="search"type="text"name="terms"value="Search..."<inputname="search"type="image"style="border:0;margin:00-9px?src="style/search.png"alt="Search"title="Search"<div<!--Endofheader.--HTMLPHP<?php#Script2.2-header.htmlif(!isset($page_title))為了防止有些PHP在包含頁(yè)頭文件時(shí)可能忘記設(shè)置$page_title,所以在此我們?cè)O(shè)置了一個(gè)默認(rèn)的頁(yè)面標(biāo)題(當(dāng)然可以使用更加明確了錯(cuò)誤報(bào)告,那么在頁(yè)面沒(méi)有設(shè)置$page_title時(shí),瀏覽器的標(biāo)題會(huì)變得很,如圖2-5所示。保存文件為headerhtml。文件的擴(kuò)展名。有些程序員喜歡使用.inc

圖2-5要確保$page_title變量的值已經(jīng)被這是個(gè)包含文件,這里我們還可以使用.inchtml作為其擴(kuò)展名,同時(shí)表示它既是一個(gè)包含文 又是一個(gè)HTML文件(以便于和全部由PHP代碼構(gòu)成的包含文件區(qū)分開(kāi)來(lái)。把從頁(yè)面特定的內(nèi)容結(jié)束到頁(yè)面末尾的內(nèi)容全部到一個(gè)新的文件,如2.3<div<divCopyright©colour_blue?<ahref="??HTML5</a>|<a?check/referer">CSS</a>?<a??from?頁(yè)腳文件包含頁(yè)面的剩余格式,包括頁(yè)面的頁(yè)腳和結(jié)束HTML文檔的。保存文件為footer.html。將兩個(gè)文件都放在Web服務(wù)器的 2.3頁(yè)腳文件完成整個(gè)HTML模板<!--#Script2.3-footer.html--<div<divCopyright©colour_blue?<ahref="??HTML5</a>|<a?/css-?<ahref="??from索引文件是模塊化程序中的主要,事實(shí)上它是唯一會(huì)被加載進(jìn)Web瀏覽器的頁(yè)面。這種構(gòu)建方法的技術(shù)術(shù)語(yǔ)叫做引導(dǎo)文件(bootstrap?le,它通常也是在基于框架的系統(tǒng)中Web頁(yè)面。這可能涉及以???合并HTML模?按照慣例來(lái)說(shuō),引導(dǎo)文件不會(huì)包含任何HTML代碼,因?yàn)檫@些必不可少的HTML代碼在文本編輯器或者集成開(kāi)發(fā)環(huán)境中新建一段PHP,并命名為index.php,2.4<?php#Script2.4-24索引頁(yè)面的控制著一切,它決定應(yīng)該包含哪個(gè)模塊、需要的配置文件,并且合并HTML模板 <?php#Script2.4-index.php *Thisisthemain*Thispageincludestheconfiguration*thetemplates,andanycontent-specific8//RequiretheconfigurationfilebeforeanyPHP//Validatewhatpageto $p= $p=}else$p= //Determinewhatpagetoswitch{case$page=$page_title='AboutThiscase$page=$page_title='Contactcase$page=$page_title='Search//Defaultistoincludethemain$page=$page_title='SiteHome //Makesurethefileif(!file_exists('./modules/'.$page))$page=$page_title='SiteHome //Includetheheader//Includethecontent-specific//$pageisdeterminedfromtheaboveinclude('./modules/'.$page); //Includethefooterfiletocompletethe $p=$p=}else$p=}要顯示的內(nèi)容是基于發(fā)送給這個(gè)頁(yè)面的值。當(dāng)用戶單擊時(shí),這個(gè)值會(huì)通過(guò)URL發(fā)送過(guò)來(lái)。當(dāng)大部分表單提交時(shí),這個(gè)值會(huì)通過(guò)$_POST發(fā)送。如果不是上述兩種情況之一,腳本就把$p設(shè)置為NULL。switchswitch{case$page=$page_title=每個(gè)模塊的文件名稱都是xxx.inc.php,我們用這種方式表示它既是一個(gè)PHP,同時(shí)也是一個(gè)包含文件。根據(jù)計(jì)算機(jī)處理擴(kuò)展名的方式,只有最后一個(gè)擴(kuò)展名是真正有效的(也就是說(shuō),如果直接運(yùn)行這種文件,它會(huì)被當(dāng)做PHP來(lái)處理。完成switch語(yǔ)句:case$page=case$page=$page_title$page=$page_title}//Endofmain每個(gè)可能的內(nèi)容模塊都包含在switch語(yǔ)句中。出于安全的目的,default語(yǔ)句是很重要的。如果$p沒(méi)有值或者不是有效值(語(yǔ)句中指定的某個(gè)值),就會(huì)使用main.inc.php文件。這是必不可少的安全步驟,因?yàn)橐恍┯脩粼诳吹秸军c(diǎn)的URL形如index.php?p=contact的時(shí)候會(huì)在瀏覽器地址欄中嘗試輸入類似index.php?p=/path/to/secret/?le這樣的內(nèi)容。在這種情if(!file_exists('/modules/'?$page))$page=$page_title='SiteHome}switch語(yǔ)句的每個(gè)條件設(shè)置的

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論