《Advanced PHP Programming》读书笔记
此書無中文版,但是寫的極好!本來想翻譯的,可是時間不允許了。
http://www.amazon.com/Advanced-PHP-Programming-George-Schlossnagle/dp/0672325616/ref=pd_rhf_dp_p_t_1
?
約定:加粗字體表示章節,由于時間關系解釋性的說明全部省略。
《高級?PHP程序設計》
簡介
PHP在企業級開發
?一個編程語言滿足下面6方面才能滿足關鍵的商業應用:
快速原型設計和實施
現代編程范式的支持
可伸縮性
高性能
互操作性
可擴展性
平臺和版本
本書主要是針對php5,更主要是使你的代碼更快,更敏捷,設計的更好。
本書基于linux編寫的。
平臺和版本
平臺和版本
第一部分 實施和開發方法
第一章 代碼風格
選擇適合你的代碼風格
代碼格式化和布局
包括行的長度,使用空白,使用SQL是最基本的技能。
?
縮進
本書使用縮進來表示代碼塊,但不能夸大其重要性。雖然php中不強制縮進,但是縮進是一個有用的工具。
考慮下面的代碼
if($month? == 'september' || $month? == 'april' || $month? == 'june' || $month? ==
'november') { return 30;
}
else if($month == 'february') {
if((($year % 4 == 0) && !($year % 100)) || ($year % 400 == 0)) {
return 29;
}
else {
return 28;
}
}
else {
return 31;
}
和下面的代碼比較,除了縮進都是相同的。
if($month == 'september' ||$month == 'april' ||$month == 'june' ||$month == 'november') {return 30;
}
else if($month == 'february') {if((($year % 4 == 0) && ($year % 100)) || ($year % 400 == 0)) {return 29;}else {return 28;}
}
else {return 31;
}
后一段代碼比前一段在邏輯上更好分辨。
?
當你使用tab代碼縮進,你需要做出一致性選擇使用硬或軟tab,硬是常規選項,而軟實際上是由一定量的空格表示,使用軟的好處是他們總是相同,我比較喜歡軟。當你使用硬,在多個開發人員使用不同的編輯器會造出不一致。
選擇tab的寬度,四個空格的標簽產生可讀的代碼。
?
?
行長
前面的第一段代碼太長,這樣不便于跟蹤和調試,應該把長行分為多行,例如:
if($month == 'september' || $month == 'april' ||$month == 'june' || $month == 'november') {return 30;
}
可以縮進對齊條件
if($month == 'september' ||$month == 'april' ||$month == 'june' ||$month == 'november')
{return 30;
}
這個方法同樣適合于函數的參數
mail("postmaster@example.foo",
???? "My Subject",
???? $message_body,
???? "From: George Schlossnagle <george@omniti.com>\r\n");
一般,我會80個字符就要換行,因為這是一個標準unix終端窗口的寬度。
?
使用空白
$lt = localtime();
$name = $_GET['name'];
$email = $_GET['email'];
$month = $lt['tm_mon'] + 1;
$year = $lt['tm_year'] + 1900;
$day = $lt['tm_day'];
$address = $_GET['address'];
?
通過空白進行邏輯分組
$name = $_GET['name'];
$email = $_GET['email'];
$address = $_GET['address'];$lt = localtime();
$day = $lt['tm_day'];
$month = $lt['tm_mon'] + 1;
$year = $lt['tm_year'] + 1900;
SQL指引
$query = "SELECT FirstName, LastName FROM employees, departments WHERE
employees.dept_id = department.dept_id AND department.Name = 'Engineering'";
?
上面的sql組織的不好,可以從以下方面修改:
關鍵字大寫;關鍵字換行;使用表的別名保持代碼整潔
$query = "SELECT firstname,lastnameFROM employees e,departments dWHERE e.dept_id = d.dept_idAND d.name = 'Engineering'";
控制流結構
兩種方式:條件和循環
?
控制結構使用大括號
php采用c語言風格,單行php條件語句不用使用大括號,例如下面的代碼是正確的:
if(isset($name))print "Hello $name";
但是,這樣會引起混亂,應該總是使用大括號
if(isset($name)) {print "Hello $name";
}
else {print "Hello Stranger";
}
始終使用大括號
條件語句中三種使用括號的風格
BSD風格我比較喜歡
if ($condition)
{// statement
}
?
GNU風格
if ($condition){// statement}
K&R 風格
if ($condition) {// statement
}
for和foreach和while
如果for或者foreach循環可以做的事情不應該使用while循環
function is_prime($number)
{if(($number % 2) != 0) {return true;}$i = 0;while($i < $number) {// A cheap check to see if $i is evenif( ($i & 1) == 0 ) {continue;}if ( ($number % $i ) == 0) {return false;}$i++;}return true;
}
不小心會增加無限循環,使用for更加自然
function is_prime($number)
{if(($number % 2) != 0) {return true;}for($i=3; $i < $number; $i++) {// A cheap check to see if $i is evenif( ($i & 1) == 0 ) {continue;}if ( ($number % $i ) == 0) {return false;}}return true;
}
對數組迭代的時候foreach比for更好
$array = (3, 5, 10, 11, 99, 173);
foreach($array as $number) {if(is_prime($number)) {print "$number is prime.\n";}
}
這樣比使用for更快,因為避免計數器的使用。
使用break和continue控制循環
不需要循環的時候使用break跳出循環
$has_ended = 0;
while(($line = fgets($fp)) !== false) {if($has_ended) {}else {if(strcmp($line, '_END_') == 0) {$has_ended = 1;}if(strncmp($line, '//', 2) == 0) {}else {// parse statement}}
}
這個例子比前面的更短,而且避免了深層次的嵌套
while(($line = fgets($fp)) !== false) {if(strcmp($line, '_END_') == 0) {break;}if(strncmp($line, '//', 2) == 0) {continue;}// parse statement
}
避免很深層的循環
常見的錯誤是在一個淺循環中使用深層嵌套
$fp = fopen("file", "r");
if ($fp) {$line = fgets($fp);if($line !== false) {// process $line} else {die("Error: File is empty);
}
else { die("Error: Couldn't open file");
}
消除不必要的嵌套
$fp = fopen("file", "r");
if (!$fp) {die("Couldn't open file");
}
$line = fgets($fp);
if($line === false) {die("Error: Couldn't open file");
}
// process $line
命名符號
function test($baz)
{for($foo = 0; $foo < $baz; $foo++) {$bar[$foo] = "test_$foo";}return $bar;
}下面的代碼使用更有意義的變量名和函數名
function create_test_array($size)
{for($i = 0; $i < $size; $i++) {$retval[$i] = "test_$i";}return $retval;
}
三類命名規則:
全局變量要使用在全局范圍
長時間存在的變量可存在于任何范圍但要包含重要信息或大塊代碼的引用
臨時變量用于小部分代碼保持臨時信息
常量和真正的全局變量
全局變量和常量要使用大寫字母,便于辨識。
$CACHE_PATH = '/var/cache/';
...
function list_cache()
{global $CACHE_PATH;$dir = opendir($CACHE_PATH);while(($file = readdir($dir)) !== false && is_file($file)) {$retval[] = $file;}closedir($dir);return $retval;
}
錯誤使用全局變量的原因:
它們可以在任何地方被改變不好定位;
污染了全局命名空間,例如使用一個全局變量命名為計數器$counter同時你還有另一個計數器也是$counter,隨著代碼的增長這種沖突越來越不可避免;
解決方案是使用一個“訪問器”函數。
global $database_handle;
global $server;
global $user;
global $password;
$database_handle = mysql_pconnect($server, $user, $password);
可以使用如下的類:
class Mysql_Test {public $database_handle;private $server = 'localhost';private $user = 'test';private $password = 'test';public function __construct(){$this->database_handle =mysql_pconnect($this->server, $this->user, $this->password);}
}
第二章中將探索更有效的方式處理這個例子,當我們處理單例模式和封裝類時。
有時候,你需要訪問一個特定的變量,像這樣:
$US_STATES = array('Alabama', ... , 'Wyoming');
這個例子中類做了太多的事情,如果你想在這里避免全局變量,你可以使用一個訪問函數全局數組使用一個靜態變量。
function us_states()
{static $us_states = array('Alabama', ... , 'Wyoming');return $us_states;
}
長時間存在的變量
應該有簡潔描述性的名稱,長時間存在的變量不一定是全局的,甚至在主題范圍內。
下面例子中變量名幫助理解代碼的意思。
function clean_cache($expiration_time)
{$cachefiles = list_cache();foreach($cachefiles as $cachefile) {if(filemtime($CACHE_PATH."/".$cachefile) > time() + $expiration_time) {unlink($CACHE_PATH."/".$cachefile);}}
}
臨時變量
臨時變量的名稱要簡明扼要。由于臨時變量通常只存在于一個小的代碼塊,所以他們并不需要有說明性名稱。 特別是用于循環的數值變量應該始終被命名為J,K,L,M,和n
等。?
比較這個例子
$number_of_parent_indices = count($parent);
for($parent_index=0; $parent_index <$number_of_parent_indices; $parent_index++) {$number_of_child_indices = count($parent[$parent_index]);for($child_index = 0; $child_index < $number_of_child_indices; $child_index++) {my_function($parent[$parent_index][$child_index]);}
}
例如
$pcount = count($parent);
for($i = 0; $i < $pcount; $i++) {$ccount = count($parent[$i]);for($j = 0; $j < $ccount; $j++) {my_function($parent[$i][$j]);}
}
這樣會更妙
foreach($parent as $child) {foreach($child as $element) {my_function($element);}
}
?多詞名稱
$numElements = count($elements);
$num_elements = count($elements);
推薦第二種命名方法,原因是:
情況發生變化,你為了保持一致性不得不$CACHEDIR和$PROFANITYMACROSET
數據庫不區分大小寫;
非英語本土人士會在字典中更好的查到。
?
函數名
函數名和正常的變量名類似的處理方式,全部小寫,多字要用下劃線分割,推薦K&R風格:
function print_hello($name)
{print "Hello $name";
}
?foo() 和bar() 反映不出你的代碼更多的信息,讓你的代碼看起來很不專業。
?
類名
參考官方的Java風格指南,類名應遵循以下規則:
一個類的名字第一個字母是大寫;
下劃線應該用來模擬嵌套的命名空間;
多字的類名應連接在一起,每個單詞的首字母應大寫。
class XML_RSS {}
class Text_PrettyPrinter {}
方法名
Java風格的串連字多字的方法名稱是第一個字母后的單詞第一個字母大寫
class XML_RSS
{function startHandler() {}
}
?命名一致性
類似目的的變量保持類似的名稱
$num_elements = count($elements);
...
$objects_cnt = count($objects);推薦下面的風格
$max_elements;
$min_elements;
$sum_elements;
$prev_item;
$curr_item;
$next_item;
匹配變量名和架構名
與數據庫中的記錄相關聯的變量名稱應該始終有相匹配的名字。
$query = "SELECT firstname, lastname, employee_idFROM employees";
$results = mysql_query($query);
while(list($firstname, $lastname, $employee_id) = mysql_fetch_row($results)) {// ...
}
下面的代碼容易混淆
$first_query = "SELECT a,bFROM subscriptionsWHERE subscription_id = $subscription_id";
$results = mysql_query($first_query);
list($a, $b) = mysql_fetch_row($results);
// perform necessary logic
$new_a = $b;
$new_b = $a;
$second_query = "UPDATE subscriptionsSET a = '$new_a',B = '$new_b'WHERE subscription_id = $subscription_id";
Mysql_query($second_query);
開發人員為了保持列名和變量名在update中一致性
$first_query = "SELECT a,bFROM subscriptionsWHERE subscription_id = $subscription_id";
$results = mysql_query($first_query);
list($b, $a) = mysql_fetch_row($results);
// perform necessary logic
$second_query = "UPDATE subscriptionsSET a = '$a',B = '$b'WHERE subscription_id = $subscription_id";
mysql_query($second_query);
這一代碼會完全混亂不堪。
?
避免代碼混亂
一致的代碼風格讓代碼看一起是清晰的
避免短的開放的標簽
php允許段標簽
<?
print "Hello $username";
?>但是不應該使用!
因為無法打印正常的XML內聯文件
<?xml version="1.0" ?>
應該使用長標簽
<?php
print "Hello $username";
? >
?
總結
以上是生活随笔為你收集整理的《Advanced PHP Programming》读书笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux下gedit显示行号
- 下一篇: 科目二补考多少钱啊?