php基礎(chǔ)個人總結(jié)
標(biāo)簽: php
以下是我在學(xué)習(xí)php基礎(chǔ)時巨税,個人總結(jié)的一些零碎知識达吞,本人文筆不好,可能會出現(xiàn)一些語句不通的情況绸罗,如有出現(xiàn)意推,歡迎各位對我嚴(yán)厲指出。我先發(fā)一些總結(jié)珊蟀,后續(xù)部分以后會陸續(xù)更新左痢,新的總結(jié)可能會在本篇繼續(xù)更新,亦或新開一篇系洛,具體的視篇幅而定俊性。
1、注釋:
php注釋基本分為單行注釋(//)描扯,和多行注釋(/**/)定页,這兩個在平時工作和學(xué)習(xí)上使用較多,但是如果在編輯大段代碼時绽诚,如果需要反復(fù)對某一部分進行注釋和反注釋(取消注釋)的測試時典徊,那么再使用這種常規(guī)的這些加注釋的方法會變得很繁瑣。
?下面我來介紹兩種注釋和反注釋的方法恩够,這種方法是我以前學(xué)習(xí)php基礎(chǔ)時一位老師介紹的卒落,個人感覺實用性很強,所以就分享給大家蜂桶。在實際應(yīng)用中只需要改一個數(shù)或一個符號就可以完成注釋和反注釋了儡毕。
第一種方法:
//注釋
/*
//注意,在頂部寫注釋開頭時不要在后面繼續(xù)寫代碼,
//否則在進行反注釋后的本行代碼還是會注釋腰湾,造成代碼顯示不全的情況
echo "<br />代碼1";
echo "<br />代碼2";
echo "<br />代碼3";
//*/
//請注意看注釋和反注釋的區(qū)別雷恃,在進行反注釋時,只需要在注釋開頭部分添加一個斜杠即可费坊。
//反注釋
//*
echo "<br />代碼1";
echo "<br />代碼2";
echo "<br />代碼3";
//*/
? 第二種方法(使用if語句):
//注釋
if(1 == 0)
{
echo "<br />代碼1";
echo "<br />代碼2";
echo "<br />代碼3";
}
//請注意看注釋和反注釋的區(qū)別倒槐,在進行反注釋時,只需要在if條件判斷部分將0改成1即可附井。
//反注釋
if(1 == 1)
{
echo "<br />代碼1";
echo "<br />代碼2";
echo "<br />代碼3";
}
以上就是注釋與反注釋的介紹讨越,這樣做可以節(jié)省在注釋完后要取消注釋時的操作時間,提高我們的編程效率永毅。
2把跨、一元運算符
一元運算符:只有一個操作數(shù)的運算符
5 + 6 兩個操作數(shù)的運算符 二元運算符
++ 自身加1
-- 自身減1
-
前置++
$num1 = 5; ++$num1; $num2 = 6; echo $num1 + ++$num2; //13
-
后置++
$num1 = 5; $num1++; $num2 = 6; echo $num1 + $num2 ++; //12
-
猜猜看
$a = 1; $b = ++$a + ++$a; echo $b; //5 $a = 1; $b = $a++ + ++$a; echo $b;//4 $a = 1; $b = $a++ + $a++; echo $b;// 3 $a = 1; $b = ++$a + $a++; echo $b;//4
總結(jié)
前置++:先加1,后參與運算
后置++:先參與運算卷雕,后加1节猿;注意:后++ 有兩個運行條件票从,滿足其一則會執(zhí)行漫雕。
⑴ 表達式?jīng)]有結(jié)束但是又被使用了(如:
a++ + $a++);⑵表達式結(jié)束了峰鄙;
上面兩個理解后浸间,下面兩個自通
前置-- :先減1,后參與運算
后置-- :先參與運算吟榴,后減1
3魁蒜、錯誤處理
(1)常見的錯誤代號
含義:指在程序運行時,發(fā)生的錯誤吩翻,系統(tǒng)會針對每種錯誤兜看,給出相應(yīng)的錯誤代號,并進行提示(報錯)狭瞎。另外细移,程序如果在運行之前檢查語法的時候就發(fā)現(xiàn)語法錯誤,也會報錯熊锭,也有一個錯誤代號弧轧。
常見錯誤代號有:
E_NOTICE:
提示性錯誤,輕微碗殷;
錯誤發(fā)生后精绎,后面的程序繼續(xù)執(zhí)行。
E_WARNING:
警告性錯誤锌妻,稍微嚴(yán)重代乃;
錯誤發(fā)生后,后面的程序繼續(xù)執(zhí)行仿粹。
E_ERROR:
嚴(yán)重錯誤/致命錯誤襟己;
錯誤發(fā)生后引谜,后面的程序不再執(zhí)行!
E_PARSE:
語法錯誤(語法解析錯誤)擎浴;
語法解釋錯誤员咽,是直接就不運行程序。
E_USER_NOTICE:
用戶自定義的提示錯誤
E_USER_WARNING:
用戶自定義的警告錯誤
E_USER_ERROR:
用戶自定義的嚴(yán)重錯誤
E_ALL:
它是一個代表“所有”錯誤的代號贮预。
說明:
- 這些錯誤代號贝室,其實只是系統(tǒng)預(yù)先設(shè)定的一些常量,他們的值大約是:1仿吞, 2滑频, 4, 8唤冈, 16.....
- 這些錯誤代號峡迷,通常只是用于對錯誤控制時進行“設(shè)置”使用。
- 他們是一系列的整數(shù)你虹,并具有一定的規(guī)律:1,2,4,8,16,32,64绘搞, 。傅物。夯辖。。
- 可以在php.ini中使用(設(shè)置)他們
(2)錯誤觸發(fā)
就是發(fā)生了一個錯誤的意思——即觸發(fā)了錯誤董饰。
有兩種情形會觸發(fā)錯誤:
程序本身有錯蒿褂,則運行時就會觸發(fā)錯誤(并提示)。
-
程序本身沒錯卒暂,但出現(xiàn)不符合預(yù)計的情形(比如數(shù)據(jù)不符合要求)啄栓。
此時程序員可以主動觸發(fā)一個錯誤,也可以說是由程序員“主動創(chuàng)建一個錯誤” 也祠。
——這就是“用戶錯誤”昙楚,包括:
? E_USER_NOTICE:
? E_USER_WARNING:
? E_USER_ERROR:
自定義錯誤觸發(fā)語法:trigger_error(“自定義錯誤提示內(nèi)容”, 自定義錯誤的代號);
//認(rèn)為觸發(fā)錯誤:
//假設(shè)年齡在0-60范圍有效:
$age = 88;
if($age > 60 || $age < 0)
{
trigger_error('年齡不符合本公司業(yè)務(wù)范圍!', E_USER_ERROR);
}else
{
echo "年齡復(fù)合要求齿坷,請點擊下一步";
}
(3)錯誤顯示設(shè)置:
如果有錯誤發(fā)生(觸發(fā)了錯誤)桂肌,默認(rèn)情況下會被顯示在頁面(即輸出的結(jié)果頁面)。
我們可以對此進行設(shè)置永淌,以決定以下兩點:
-
設(shè)置display_errors以決定是否顯示錯誤:
? 在php.ini中設(shè)置: display_errors = On或Off 崎场,這里設(shè)置,影響所有使用該php語言引擎的代碼(網(wǎng)站頁面)遂蛀;
? 在php文件中設(shè)置: ini_set(‘display_errors’, 1或0); //1表示顯示谭跨,0不顯示 。在這里設(shè)置,只影響當(dāng)前網(wǎng)頁代碼本身螃宙。
-
設(shè)置error_reporting以決定顯示哪些類型的錯誤:
? 在php.ini中設(shè)置: error_reporting = 錯誤代號1 | 錯誤代號2 | ..... //(要顯示的就寫出來蛮瞄,或者可以寫E_ALL, 表示顯示所有)。
? 在代php文件中谆扎,道理類似:ini_set(‘error_reporting’, 錯誤代號1 | 錯誤代號2 | .....)
(4)錯誤日志設(shè)置
如果有錯誤發(fā)生(觸發(fā)了錯誤)挂捅,默認(rèn)情況下不會將錯誤信息記錄(保存)下來。
我們可以對此進行設(shè)置堂湖,以決定以下兩點:
-
設(shè)置log_errors以決定是否記錄錯誤:
? php.ini中設(shè)置:
log_errors = On 或 Off
闲先,代碼文件中設(shè)置:ini_set (‘log_errors’, 1或0)
-
設(shè)置error_log以決定記錄到哪里:
? 通常,就設(shè)置為一個文件名无蜂,php系統(tǒng)會在網(wǎng)站的每個文件夾下都建立該文件伺糠,并記錄錯誤。php.ini中:
error_log = error.txt;
//它是純文本的 斥季。代碼中:ini_set(“error_log”, ‘error.txt’);
//界面不顯示錯誤训桶,但是希望記錄記錄下來
ini_set("display_errors", 0);//不顯示錯誤
ini_set("log_errors", 1);//記錄日志
ini_set("error_log", "myError.txt");//記錄到該文件中
echo $i;//E_NOTICE錯誤
func1();//E_ERROR錯誤
(5)自定義錯誤處理
分兩步:
- 聲明錯誤發(fā)生時,由我們自己來處理——設(shè)定一個錯誤處理的函數(shù)名酣倾。
- 定義該函數(shù)舵揭,在函數(shù)中詳細設(shè)定錯誤的處理情況:怎么顯示,顯示什么灶挟,怎么記錄琉朽,記錄什么毒租。
特別注意:
如果發(fā)生系統(tǒng)的E_ERROR級別錯誤稚铣,則還是不會去調(diào)用我們的自定義錯誤處理機制,還是按系統(tǒng)的處理方式來處理墅垮。
//第1步:聲明自定義錯誤處理函數(shù):
//一旦發(fā)生錯誤惕医,請找函數(shù)myErrorControl去處理
set_error_handler("myErrorControl");
//第2步:定義該函數(shù):
function myErrorControl($errCode, $errMsg, $errFile, $errLine){
//此函數(shù)中就可以任意發(fā)揮:想怎么處理就怎么處理!
echo "<h1>發(fā)生錯誤算色!</h1>";
//這里抬伺,可以來決定(通過if或其他邏輯判斷)來顯示或記錄那些錯誤信息
//下面是演示"顯示"這個功能:
echo "<br>錯誤代號:" . $errCode;
echo "<br>錯誤消息:" . $errMsg;
echo "<br>錯誤文件:" . $errFile;
echo "<br>錯誤行號:" . $errLine;
//還可以去“記錄錯誤”:記錄到文件,或記錄到數(shù)據(jù)庫灾梦。峡钓。。
}
echo $i; //E_NOTICE錯誤若河,會調(diào)用自定義錯誤處理函數(shù)
echo $j; //同上能岩。
func1(); //E_ERROR錯誤,不會調(diào)用自定義錯誤處理函數(shù)
4萧福、系統(tǒng)常用函數(shù)
(1)跟函數(shù)有關(guān)的函數(shù)
function_exists(“函數(shù)名”)
:判斷一個函數(shù)是否已經(jīng)存在拉鹃;
func_get_arg( $n )
:在函數(shù)內(nèi)部可用,用于獲得第n個實參(n從0開始算起) ;
func_get_args()
: 在函數(shù)內(nèi)部可用膏燕,用于獲得所有實參钥屈,結(jié)果是一個數(shù)組;
func_num_args()
: 在函數(shù)內(nèi)部可用坝辫,用于獲得實參的個數(shù)篷就。
上面3個函數(shù),可以讓我們在自定義的函數(shù)內(nèi)部近忙,直接訪問(使用)實參數(shù)據(jù)腻脏,而不依賴于形參變量。這種特性银锻,可以給我們定義某種“不確定有幾個數(shù)據(jù)需要計算的”場合永品。
(2)字符串有關(guān)常用函數(shù)
輸出與格式化:
- echo,輸出字符击纬,可以輸出多個
- print鼎姐,輸出字符
- printf(),輸出格式化字符
- print_r()更振,輸出簡化性“數(shù)據(jù)信息”
- var_dump()炕桨,輸出完整性“數(shù)據(jù)信息”
字符串去除與填充:
trim(),去除兩端字符
ltrim()肯腕,去除左端字符
rtrim()献宫,去除右端字符
str_pad(),將一個字符填充到指定的長度
-
implode()实撒,將一個數(shù)組的每一項使用某個字符“串起來”成為一個“長的字符串”蘸际,別名: join()
$arr = array(“12”, “345”, “abc”);
$str = implode( $arr, “|”);
,結(jié)果:”12|345|abc” -
explode()捉偏,將一個“長的字符串”牲阁,使用某個字符進行“分割”得到一個數(shù)組
$v1 = '12, 345, abc';
$re = explode($v1, ",");
結(jié)果為: array(“12”, “345”, “abc”); str_split():按給定的長度分割字符串
字符串截取:
- substr()负敏,截取字符串的前多少個字符
- strchr()贡茅, 查找首次出現(xiàn)的字符,截取出該字符往后的所有字符
- strrchr()其做, 反向查找
字符串替換:str_replace()顶考, substr_replace()
字符串長度與位置:
- strlen(), 取得字符串的長度
- strpos()妖泄, 取得某個字符在某個字符串中的首次出現(xiàn)的位置
- strrpos()驹沿,取得某個字符在某個字符串中的最后一次出現(xiàn)的位置
- mb_strlen(),求該字符串的“字符個數(shù)”
字符轉(zhuǎn)換:
- strtolower()浮庐, 將字符串轉(zhuǎn)化為小寫
- strtoupper()甚负, 將字符串轉(zhuǎn)化為大寫
- lcfirst()柬焕, 第一個字母轉(zhuǎn)換小寫
- ucfirst(),第一個字母轉(zhuǎn)換大寫
- ucwords()梭域, 第一個單詞轉(zhuǎn)換大寫
特殊字符處理:
- nl2br()斑举,將換行符替換為”<br>”標(biāo)簽
- addslashes(), 將一些特殊字符(‘, “, \ )轉(zhuǎn)換成“轉(zhuǎn)義形式”(\’, \”, \\)
- htmlspecialchars()病涨, 將html中的字符轉(zhuǎn)換為“實體字符”富玷,比如:”<”轉(zhuǎn)換為
<
- htmlspecialchars_decode(),跟上面的相反過程
(3)常用數(shù)學(xué)函數(shù)
- max()既穆,取得若干個數(shù)據(jù)的最大值
- min()赎懦,取得若干個數(shù)據(jù)中的最小值
- round(),對某個數(shù)據(jù)進行四舍五入(可以設(shè)定保留幾位小數(shù))
- ceil()幻工,對某個數(shù)“向上取整”:將一個數(shù)據(jù)往上找出其小的一個整數(shù)(含其本身)励两。
? $n1 = ceil(4.1);
//5
- floor(),對某個數(shù)“向下取整”:將一個數(shù)據(jù)往下找出其大的一個整數(shù)(含其本身)囊颅。
? $n1 = floor(4.1);
//4
abs()当悔,取得某個數(shù)據(jù)的絕對值
sqrt(),計算某個數(shù)的開方值
-
pow()踢代,對某個數(shù)進行“冪運算”(就是獲得某個數(shù)的若干次方)
$n1 = pow(3, 2);
//3的2次方的結(jié)果為9 rand()盲憎,獲得某兩個數(shù)之間的隨機整數(shù)(含該兩個數(shù))
-
mt_rand(),獲得某兩個數(shù)之間的隨機整數(shù)(含該兩個數(shù))
$n1 = mt_rand(0, 10);
//隨機數(shù)在0-10之間
(4)常用數(shù)組函數(shù)
- max()胳挎,獲取一個數(shù)組中的最大值
- min()饼疙,獲取一個數(shù)組中的最小值
- count(),獲取一個數(shù)組的元素個數(shù)
- in_array()慕爬,判斷一個數(shù)據(jù)是否在指定數(shù)組中窑眯。語法形式:
數(shù)組, 數(shù)據(jù)); //結(jié)果true或false
- range()澡罚,生成某個范圍的連續(xù)值的數(shù)組伸但,比如range(3, 9)會得到數(shù)組:array(3, 4, 5, 6, 7, 8, 9, );
- array_keys()肾请,取出一個數(shù)組中的所有“鍵”并放入一個索引數(shù)組中
- array_values()留搔,取出一個數(shù)組中的所有“值”并放入一個索引數(shù)組中
- array_push(),將一個或多個數(shù)據(jù)放入一個數(shù)組的“末端”
- array_pop()铛铁,將一個數(shù)組的最后一個單元刪除隔显,并返回該單元的值
- array_reverse(),將一個數(shù)組的所有單元的順序進行反轉(zhuǎn)(最前的放最后饵逐,最后的放最前)
常用的排序數(shù)組
- sort($arr1)括眠,按值排序,正序,不保留原始鍵
- rsort($arr1),按值排序,倒序,不保留原始鍵
- asort()倍权,按值排序,正序,保留原始鍵
- arsort()掷豺,按值排序,倒序,保留原始鍵
- ksort()捞烟,按鍵排序,正序,不保留原始鍵
5、文件上傳
(1)文件上傳原理
- 上傳文件当船,就是將文件從瀏覽器端傳到服務(wù)器端
- 上傳文件题画,必須使用<form>標(biāo)記來向服務(wù)器端發(fā)數(shù)據(jù)
- 上傳文件,<form>標(biāo)記的method屬性值必須是POST
- 上傳文件德频,<form>標(biāo)記的enctype屬性值必須是multipart/form-data
- 上傳文件苍息,必須使用<input type = ‘file’ name=’upload’>標(biāo)記實現(xiàn)
<form action="./upload.php" method="post" name='form1' enctype="multipart/form-data">
上傳圖片:<input type="file" name="uploadFile">
<input type="submit" value="上傳">
<input type="hidden" value="upload" name='ac'>
</form>
(2)超全局變量數(shù)組 $_FILES
使用$_FILES數(shù)組,來獲取上傳文件的信息
//獲取上傳文件數(shù)據(jù)
print_r($_FILES);
//可以打印出上傳文件的信息壹置,如下:
/**
*Array
*(
* [uploadFile] => Array
* (
* [name] => 上傳的文件名
* [type] => 文件的MIME類型
* [tmp_name] => 文件在服務(wù)器臨時位置
* [error] => 錯誤編號
* [size] => 文件大小
* )
*)
(3)上傳文件錯誤代碼
錯誤代碼 | 含義 |
---|---|
0 | 沒有錯誤發(fā)生竞思,文件上傳成功 |
1 | 上傳的文件超過了php.ini中upload_max_filesize選項限制的值 |
2 | 上傳文件的大小超過了HTML表單中MAX_FILE_SIZE選項指定的值 |
3 | 文件只有部分被上傳 |
4 | 沒有文件被上傳 |
6 | 招不到臨時文件夾 |
7 | 文件寫入失敗 |
(4)查看上傳的臨時文件位置
- 上傳文件的默認(rèn)臨時目錄,如果沒有指定php.ini配置項upload_tmp_dir的值钞护,則使用操作系統(tǒng)臨時目錄(c:\windows\temp)盖喷。通過phpinfo()函數(shù)查看
- 為什么在 c:\windows\temp 中看不到上專文件呢?因為臨時文件是短暫存在的难咕,也就是在腳本執(zhí)行完畢后传蹈,就消失了
//延遲后再執(zhí)行一下腳本,用于觀察生成的臨時文件
sleep(10);
//獲取上傳文件數(shù)據(jù)
print_r($_FILES);
//上傳的臨時文件步藕,臨時文件會在網(wǎng)頁執(zhí)行完畢后刪除惦界,因此,需要在臨時文件刪除前咙冗,移動到永久目錄下
(5)將上傳文件移動到新位置
- 描述:本函數(shù)檢查并確保由 filename 指定的文件是合法的上傳文件(即通過 PHP 的 HTTP POST 上傳機制所上傳的)沾歪。如果文件合法,則將其移動為由 destination 指定的文件雾消。最好在臨時文件沒有消失前移動
- 語法:
bool move_uploaded_file ( string $filename , string $destination )
- 參數(shù):
destination立润,指定新的文件名路徑
- 注意:如果文件已經(jīng)存在狂窑,則會覆蓋操作
//將上傳的臨時文件,移動到網(wǎng)站根目錄下
$tmp_name = $_FILES['uploadFile']['tmp_name'];
$dst_name = "./upload/" . $_FILES['uploadFile']['name'];
move_upload_file($tmp_name, $dst_name);
(6)上傳文件的相關(guān)配置(php.ini)
- upload_tmp_dir配置:修改上傳文件的臨時目錄
- upload_max_filesize配置:上傳單個文件的大小限制桑腮,默認(rèn)為2MB
- post_max_size配置:規(guī)定上傳多個文件的總大小泉哈,默認(rèn)為8MB
- max_file_uploads配置:規(guī)定最多上傳的文件個數(shù),默認(rèn)為20個
- file_uploads配置:上傳功能是否開啟破讨,默認(rèn)為on
file_uploads = On 是否開啟文件上傳功能
upload_tmp_dir = 指定上傳臨時文件位置丛晦,默認(rèn)為c:\windows\temp
upload_max_filesize = 2M 上傳單個文件的大小
max_file_uploads = 20 一次性上傳文件總數(shù)
(7)獲取文件路徑信息
- 描述:返回文件路徑的信息
- 語法:
mixed pathinfo ( string $path [, int $options = PATHINFO_DIRNAME | PATHINFO_BASENAME | PATHINFO_EXTENSION | PATHINFO_FILENAME ] )
- 參數(shù):
- $path,要解析的路徑
- $options提陶,如果省略烫沙,返回全部單元,取值有:PATHINFO_DIRNAME(目錄名稱)隙笆、PATHINFO_BASENAME(文件名稱)锌蓄、PATHINFO_EXTENSION(擴展名)升筏、PATH_FILENAME(文件名)
(8)檢查數(shù)組中是否存在某個值
- 描述:檢查數(shù)組中是否存在某個值
- 語法:bool in_array ( mixed
arr )
- 參數(shù):
arr原數(shù)組
(9)生成唯一ID
- 描述:生成一個唯一ID
- 語法:
string uniqid ([ string $prefix = "" [, bool $more_entropy = false ]] )
- 參數(shù):
- $prefix前綴字符串瘸爽,如果省略仰冠,返回字符串長度為13
- $more_entropy后綴字符集,如果省略蝶糯,返回字符串長度為23
(10)實例:單個文件上傳
//判斷表單是否提交
if(isset($_POST['ac']) && $_POST['ac'] == 'upload')
{
//1洋只、判斷上傳有沒有錯誤發(fā)生
if($_FILES['uploadFile']['error'] != 0)
{
echo '上傳文件有錯誤發(fā)生!';
die();
}
//2昼捍、上傳文件大小不能超過1MB
if($_FILES['uploadFile']['size'] > 1024 * 1024)
{
echo '上傳文件超過了1MB的最大限額识虚!';
die();
}
//3、判斷上傳的文件是不是圖片
$arr = array('jpg', 'gif', 'png');
//4妒茬、取出上傳文件的擴展名
$ext = pathinfo($_FILES['uploadFile']['name'], PATHINFO_EXTENSION);
if(!in_array($ext, $arr))
{
echo '上傳的類型不是圖片担锤!';
die();
}
//5、移動文件
$tmp_name = $_FILES['uploadFile']['tmp_name'];
$dst_name = './upload/' . uniqid('s_', true) . '.' . $ext;
move_uploaded_file($tmp_name, $dst_name);
echo '<br>文件:' . $_FILES['uploadFile']['name'] . '上傳成功乍钻!';
}else
{
echo '非法操作肛循!';
}
(11)實例:多個文件上傳
<form action="./upload3.php" method="post" name='form1' enctype="multipart/form-data">
上傳圖片1:
<input type="file" name="uploadFile[]"><br> 上傳圖片2:
<input type="file" name="uploadFile[]"><br> 上傳圖片3:
<input type="file" name="uploadFile[]"><br>
<input type="submit" value="上傳">
<input type="hidden" value="upload" name='ac'>
</form>
//判斷表單是否提交
if(isset($_POST['ac']) && $_POST['ac'] == 'upload')
{
//把三維數(shù)組變成兩維數(shù)組
$arr = $_FILES['uploadFile'];
//循環(huán)數(shù)組
foreach($arr['name'] as $key => $name)
{
//判斷文件名是否為空,如果不空银择,則移動文件
if($name != '')
{
$ext = pathinfo($name, PATHINFO_EXTENSION);
$tmp_name = $arr['tmp_name'][$key];
$dst_name = './upload/' . uniqid() . '.' . $ext;
move_uploaded_file($tmp_name, $dst_name);
}
}
echo '上傳文件成功多糠!';
}
6、多態(tài)
多態(tài)通俗的說:就是多種狀態(tài)浩考,就是指在面向?qū)ο笾屑锌祝瑢ο螅悾┰诓煌闆r下的多種狀態(tài)(根據(jù)使用的上下文)∥瞿酰可以通過繼承父類或者實現(xiàn)接口而來體現(xiàn)多態(tài)搭伤。
特點:
- PHP可以根據(jù)傳入的對象類型不同,調(diào)用對應(yīng)的該對象的方法袜瞬;
- PHP天生就是多態(tài)語言怜俐。因為你給它什么,它就是什么邓尤。
① 多態(tài)的表現(xiàn)
先看一個簡單的案例來說明一下多態(tài):
有一個Food食物類拍鲤,F(xiàn)ood下有兩個子類:Fish魚肉類和Bone骨頭類
有一個Animal動物類,Animal下有兩個子類:Cat貓類和Dog狗類
還有一個Master主人類裁赠,主人類可以用于類型約束殿漠。
實現(xiàn)下主人給動物喂食:
header("content-type:text/html;charset=utf-8");
//多態(tài)
class Animal
{
public $name;
public function __construct($name)
{
$this->name = $name;
}
}
class Dog extends Animal
{
public function showInfo()
{
echo $this -> name;
}
}
class Cat extends Animal
{
public function showInfo()
{
echo $this -> name;
}
}
class Food
{
public $name;
public function __construct($name)
{
$this -> name = $name;
}
}
class Fish extends Food
{
public function showInfo()
{
echo $this -> name;
}
}
class Bone extends Food
{
public function showInfo()
{
echo $this -> name;
}
}
$dog = new Dog('德國黑背');
$cat = new Cat('波斯貓');
$fish = new Fish('鯉魚');
$bone = new Bone('大棒骨');
class Master
{
public $name;
public function __construct($name)
{
$this -> name = $name;
}
//喂食
public function feed($animal, $food)
{
echo '<br>';
$animal -> showInfo();
echo '喜歡吃';
$food -> showInfo();
}
}
//創(chuàng)建一個主人
$master = new Master('小明');
$master -> feed($dog, $bone);
$master -> feed($cat, $fish);
這種代碼,就是體現(xiàn)的是PHP的多態(tài)佩捞。但是有人提出質(zhì)疑:這也太靈活了,這PHP的語法過于松散蕾哟,很容易造成類型沒有約束一忱。
傳進去一個字符串如果調(diào)不起來莲蜘,不就報錯了么?雖然傳進去可以提示報錯帘营,但是為什么一定要等人家報錯你再告訴別人錯了呢票渠。應(yīng)該在傳進的形參的地方,入口這個地方約束一下芬迄,這是更好的一種多態(tài)问顷。這樣也是對我們的程序是一種保護。
如果不加約束禀梳,完全可以在傳參的時候反著傳一下比如$master -> feed($fish, $cat);
這樣運行起來也很流暢杜窄,但是這個邏輯就不太對了。你這鯉魚怎么能吃一只貓呢算途?
所以說在傳參的地方加上一個約束條件塞耕,這樣可以限制傳入?yún)?shù)的類型,也是更好的體現(xiàn)出多態(tài)
比如說public function feed(Animal $animal, Food $food){}
有一點要注意嘴瓤,就是在傳參的地方Animal不能寫Dog扫外,如果你這么寫了,那么$cat就傳不進來了廓脆。但是如果寫的條件是Animal 筛谚,那么它的子類就都可以傳進來。這就是很有效的防護機制停忿。
下面就把優(yōu)化部分的代碼來再寫一下:
class Master
{
public $name;
public function __construct($name)
{
$this -> name = $name;
}
//喂食
public function feed(Animal $animal, Food $food)
{
echo '<br>';
$animal -> showInfo();
echo '喜歡吃';
$food -> showInfo();
}
}
//創(chuàng)建一個主人
$master = new Master('小明');
$master -> feed($dog, $bone);
$master -> feed($cat, $fish);
這樣寫的代碼的優(yōu)越性刻获,還可以體現(xiàn)出一點就是,你在Animal的子類再添加羊類瞎嬉,老虎類蝎毡,在Food的子類添加草類和兔子類,那么羊吃草氧枣,老虎吃兔子沐兵,Master這個主人類都不用動,代碼照樣可以跑起來便监。這樣非常容易進行代碼的維護扎谎。
所以別人問到你多態(tài)有什么好處時,回答:有利于代碼的維護和擴展烧董。這就OK了毁靶。
② 重載也是多態(tài)的一種表現(xiàn)
說到重載,php的重載和Java的重載是兩個不一樣的概念逊移,php的重載是指動態(tài)地"創(chuàng)建"類屬性和方法预吆,我們是通過魔術(shù)方法來實現(xiàn)的 。雖然像Java那樣的重載在php中是不支持的胳泉,但是php使用魔術(shù)方法__call()
時也是可以實現(xiàn)出來拐叉,這種重載也可以展現(xiàn)出多態(tài)的效果岩遗。
走一下代碼來說明一下:
class A
{
public function test1($p)
{
echo 'test1 <br>';
print_r($p);
echo '<hr>';
}
public function test2($p)
{
echo 'test2 <br>';
print_r($p);
echo '<hr>';
}
public function __call($method, $p)
{
if(count($p) == 1)
{
$this -> test1($p);
}elseif (count($p) == 2)
{
$this -> test2($p);
}
}
}
$a = new A();
$a -> f1(11, 45);
echo '<br>';
$a -> f1(45);
這樣一來,php就實現(xiàn)了出現(xiàn)同一方法的不同參數(shù)時凤瘦,可以走不一樣的方法了宿礁。
再來個題外話:
當(dāng)通過子類去訪問父類的屬性時,如果這個屬性被子類繼承蔬芥,則輸出子類的值梆靖,如果沒有繼承,則輸出父類的值笔诵。
7返吻、面向?qū)ο笤O(shè)計模式—單例模式
- 描述:一個類只能創(chuàng)建一個實例對象,不管用什么辦法都無法創(chuàng)建第2個對象嗤放。
- 要求(三私一公)
- 一私:私有的靜態(tài)的保存對象的屬性
- 一私:私有的構(gòu)造方法思喊,阻止類外new對象
- 一私:私有的克隆方法,阻止類外clone對象
- 一公:公共的靜態(tài)的創(chuàng)建對象的方法
class Db
{
//私有的靜態(tài)的保存對象的屬性
private static $obj = NULL;
//私有的構(gòu)造方法:阻止類外new對象
private function __construct(){}
//私有的克隆方法:阻止類外clone對象
private function __clone(){}
//公共的靜態(tài)的創(chuàng)建對象的方法
public static function getInstace()
{
//判斷當(dāng)前類的對象是否存在
if(!self::$obj instanceof self)
{
//如果當(dāng)前類的對象不存在次酌,則創(chuàng)建并保存它
self::$obj = new self;
}
//返回當(dāng)前類的對象
return self::$obj;
}
}
//創(chuàng)建數(shù)據(jù)庫類的對象
$db1 = Db::getInstance();
$db2 = Db::getInstance();
var_dump($db1, $db2);//通過打印信息恨课,可以看到兩個對象是同一個對象
單例設(shè)計模式,不管調(diào)用多少次岳服,總是一個對象剂公!
8、面向?qū)ο笤O(shè)計模式—工廠設(shè)計模式
(1)什么是工廠設(shè)計模式
- 根據(jù)傳遞不同的類名參數(shù)吊宋,返回不同類的對象
- 工廠模式纲辽,就是生產(chǎn)各種的不同類的對象
- 工廠模式,改變了在類外使用new關(guān)鍵字創(chuàng)建對象的方式璃搜,改成了在工廠類中創(chuàng)建類的對象
- 在類的外部我們無法控制類的行為拖吼,但在類內(nèi)部自己可以控制類的行為
(2)工廠設(shè)計模式的要求
- 工廠類中的方法,應(yīng)該是公共的靜態(tài)的方法
- 工廠類中有一個私有的靜態(tài)的保存對象的屬性(單例工廠模式)
- 該方法功能:就是根據(jù)傳遞的不同參數(shù)这吻,去創(chuàng)建不同的類實例
- 提示:工廠設(shè)計模式吊档,一般會與單例設(shè)計模式搭配使用
(3)工廠設(shè)計模式的簡單應(yīng)用
./app.php
header("Content-type:text/html;charset=utf-8");
//類的自動加載
spl_autoload_register(function($className){
//構(gòu)建類文件的真實路徑
$filename = "./libs/$className.class.php";
//如果類文件存在,則包含進來
if(file_exists($filename)) require_once($filename);
});
//創(chuàng)建狗狗類對象
$dogObj = Factory::getInstance("Dog");
$dogObj -> showInfo();
echo "<br>";
//創(chuàng)建貓貓類對象
$catObj = Factory::getInstance("Cat");
$catObj -> showInfo();
./libs/Factory.class.php
//定義最終的工廠類:生產(chǎn)不同類對象的工廠
final class Factory
{
//公共的靜態(tài)的不同類對象:類名可以是變量名
public static function getInstance($className)
{
//返回創(chuàng)建的不同類對象唾糯,類名稱可以使變量名
return new $className();
}
}
./libs/Dog.class.php
//定義最終的狗狗類
final class Dog
{
private $name = '哮天犬';
private $food = '大棒骨';
public function showInfo()
{
echo "{$this -> name}喜歡吃{$this -> food}";
}
}
./libs/Cat.class.php
//定義最終的貓貓類
final class Cat
{
private $name = '加菲貓';
private $food = '小金魚';
public function showInfo()
{
echo "{$this -> name}喜歡吃{$this -> food}";
}
}
(4)單例工廠類的實現(xiàn)
將(3)中的Factory.class.php代碼改成一下內(nèi)容:
//定義最終的工廠類:生產(chǎn)不同類對象的工廠
//工廠類本身不創(chuàng)建對象
final class Factory
{
//私有的靜態(tài)的保存對象的數(shù)組
private static $arrObj = [];
//公共的靜態(tài)的創(chuàng)建不同類對象的方法
public static function getInstace($className)
{
//判斷當(dāng)前類的對象是否存在
if(empty(self::$arrObj[$className]))
{
self::$arrObj[$className] = new $className;
}
//返回創(chuàng)建的不同類對象怠硼,類名可以是變量名
return self::$arrObj[$className];
}
}
在Cat.class.php和Dog.class.php代碼的類中增加兩個私有方法:
private function __construct() {}
private function __clone() {}
就可以完成單例工廠。
9移怯、無限級分類
(1)無限級分類原理(文章表為例)
① 讀取原始的文章分類數(shù)據(jù)到內(nèi)存中
② 將原始的文章分類數(shù)據(jù)香璃,轉(zhuǎn)成無限級分類數(shù)據(jù)(有層級關(guān)系)
③ 轉(zhuǎn)換的原則:
? 從根菜單開始,一層一層往下查找舟误,把找到的復(fù)合條件的菜單葡秒,放到臨時數(shù)組$categorys中。
? 菜單的縮進空格數(shù):菜單層級 * 空格數(shù)
? 菜單層級:根據(jù)函數(shù)遞歸調(diào)用的次數(shù)
(2)案例(文章表為例)
只寫主要代碼了,其余的像命名空間什么的偷懶不寫了哈同云。
① 文章分類控制器
final class CategoryController
{
public function index()
{
//獲取原始的分類數(shù)據(jù)
$categorys = ...
//獲取無限級分類數(shù)據(jù)
$categorys = CategoryModel::getInstance() -> categoryList($categorys);
//向視圖賦值
...
}
}
② 文章分類模型
final class CategoryModel
{
//受保護的數(shù)據(jù)表名稱
protected $table = "category";
//靜態(tài)變量:方法或函數(shù)調(diào)用完畢糖权,該變量不會消失堵腹;
//注意事項:靜態(tài)變量只在函數(shù)或方法第1次調(diào)用初始化炸站,以后不再初始化;
//靜態(tài)變量只能定義在函數(shù)或方法內(nèi)疚顷。
/**
* [categoryList description]
* @param $arrs [原始的分類數(shù)據(jù)]
* @param $level [菜單層級,初始值為0]
* @param $pid [上次遞歸傳遞過來的id值]
* @return $categorys [description]
*/
//獲取無限級分類的方法
public function categoryList($arrs, $level = 0, $pid = 0)
{
//定義靜態(tài)變量,用于存儲每次遞歸找到的數(shù)據(jù)
static $categorys = [];
//循環(huán)原始的分類數(shù)組
foreach ($arrs as $arr)
{
//如果本次pid和傳遞過來的id相等的話,就找到了下層菜單
if($arr['pid'] == $pid)
{
$arr['level'] = $level;//給數(shù)組添加level元素
$categorys[] = $arr;
//遞歸調(diào)用
$this->categoryList($arrs, $level + 1, $arr['id']);
}
}
//返回?zé)o限級分類的數(shù)組
return $categorys;
}
}
③ 文章分類視圖
<!-- 使用smarty模板 -->
<{foreach $categorys as $category}>
<tr>
<td>...</td>
<td>
<!-- str_repeat()字符串重復(fù)的函數(shù) -->
<!-- level:菜單層級 -->
<{str_repeat('----', $category.level * 2)}>
<!-- classname:分類名稱 -->
<{$categoty.classname}>
</td>
<td>...</td>
</tr>
<{/foreach}>