帶你深入了解php與C語言的區別

2020-07-16 10:04:21

如果你學過C語言,現在想學習PHP,第一步當然是掌握基本語法。PHP的基本語法與C極其相似,但也有一些獨特之處,本文通過對比的方式,按照學習C語言語法的順序,介紹PHP的基本語法,希望能幫助熟悉C的人快速入門。

首先明確一個思想,PHP語法與C最大的不同之處在於PHP重實用,而C重原理。學習C的語法,培養人嚴謹的思維習慣,對於了解計算機的工作原理是很有幫助的。一個學過C的人開始學PHP,會對PHP過於寬鬆的語法感到不適應。

PHP的創始人是為了更新自己的主頁而設計PHP的,不是像C的創始人那樣為了開發作業系統,這是兩者語法風格不同的根本原因。

明確了這個思想,我們就按照資料型別、常數、變數、運算子與表示式、流程控制、函數、陣列這樣的順序來一一介紹PHP的基本語法並與C相對照。

由於是入門,所以我們只沿著主幹道前進,路邊有很多美麗的風景,像正規表示式之類,我們以後再專題探索。

PHP的資料型別

PHP與C的一個顯著不同是:不管常數還是變數都不需要先定義後使用(類中的變數除外),PHP根據第一次賦值的情況自動決定資料型別。

想想當年學習C語言的時候,我們曾感到先定義後使用很麻煩(但是「長大後」(我是指學會C後)都體會到了它的好處),常常忘記定義,而現在少了這條規矩,反而有點不適應了。

PHP的基本變數型別有整型(Integer)、浮點型(Float)、字串(String)(這是C沒有的,但C++有String類)以及布林型(Boolean)(C沒有,但是C++有)。構造型別有陣列和物件。此外還有兩個特殊型別:空值(NULL)(C也有)和資源(Resource)。

常數

在PHP中定義常數的方式在學習C的人看來有點不可思議,竟然是用一個define函數實現的,PHP的函數實在是太厲害了,後面我們會看到定義陣列也是由函數完成的,我們真得感謝PHP無比豐富的函數庫,它們成就了PHP的易用和強大。

define函數原型:bool define(string name,value,[,bool case_insensitive])

第三個引數如果是TRUE,則表示常數名是大小寫不敏感的,反之就是敏感的,預設是敏感的。我們還是遵照習慣,保持常數名稱大小寫敏感吧。

例:

複製PHP內容到剪貼簿

PHP程式碼:

 <?php
  define(「C1」,」Hello
 PHP World!」);
  echo C1;
?>

以上程式碼的執行結果是輸出常數C1的值(Hello PHP World!)。

這裡順便介紹一下,<?php和?>是PHP程式碼的定界符,將PHP程式碼同HTML程式碼區分出來,PHP程式碼的語句以分號結束,這是我們習慣的,另外PHP的註釋符號也與C一樣,你該知道的,我就不說了……

這個echo就相當於C的printf或C++的cout,但是嚴格地說不是格式化的輸出,要想格式化也很容易,你把HTML程式碼寫進去就行了,比如你要輸出結束後換行,那你就寫成define(「C1」,」Hello PHP World!<br>」);好了。

注意,PHP也支援‘n’作為換行符,但是它的含義僅僅相當於在HTML裡敲個迴車,瀏覽器裡看還是在一行上的。

變數

除了不用定義,C語言使用者最不習慣的就是所有的變數名前都要帶個$,你可能會抱怨PHP的設計者太財迷了,但抱怨完了你還得這麼寫,寫PHP程式,Shift鍵的使用率陡增!

我突然發現一個這樣做的好處是:常數不帶$,因此常數與變數的區分變得很明顯,更重要的是,你再也不用擔心自定義變數名同PHP關鍵字衝突了,你可以定義一個變數叫$if,$for等(當然,正式情況下還是不要這樣做的好,過過癮就行了)。

與C相同的是,PHP的變數名是大小寫敏感的,並且命名方式遵循C識別符號的命名原則,還記得嗎?

如果你懂點C++,知道參照的概念,下面這段就可以跳過,只要記住PHP也支援參照。否則花點時間看下面這段或是去看看C++參照的概念也行。

複製PHP內容到剪貼簿

PHP程式碼:

<?php
$var1=100;
$var2=&$var1;
$var2=200;
echo $var1.」<br>」;
echo $var2;
?>

這段程式碼的執行結果是輸出兩個200,分別是$var1和$var2的值,輸出的時候為了清楚加了個換行符,PHP裡句點(.)是字串的連線符。

為什麼只給$var2賦了200,而$var1也變成了200呢,你還可以試試只改變$var1的值,你會發現這兩個變數似乎被綁在一起了。

其實語句$var2=&$var1;中的&符號的含義是將變數名$var2也指向$var1所在的儲存空間,也就是說$var2並不是一個新變數,而是$var1的另一個名字,它們對應的是同一段記憶體空間,不管使用誰都是存取的同一個變數,$var2就叫做對$var1的參照。

參照有什麼好處?以後再說。C語言的基本概念(變數名、變數地址、變數值)清楚的話,理解起來應該沒有什麼困難,如果基本概念不清楚,還是先「溫故」再「知新」吧。

順便說一個有意思的事,如果你在把上面的echo語句寫成:

echo「The value of $var1 is」.$var1.」<br>」;

那麼你得到的輸出將是:

The value of 200 is 200

還記得嗎,在初學C語言時你很可能犯過把變數名放在字串裡想輸出它的值,結果得到的是變數名,而現在,你的「理想」實現了,而你卻又不習慣了,呵呵。

原來PHP在使用雙引號作為字串的定界符時,會自動把變數名替換成相應的值,這樣的做法使得我們輸出含變數的字串時變得非常方便,一對雙引號下來就可以了。如果你想保持變數名原樣輸出,那麼可以用單引號做字串的定界符(當然還有其它辦法,你可以仔細研究一下PHP的字串)。

還是要感謝C的嚴格要求,如果C像PHP這樣的話,我們恐怕到現在也搞不清變數名、變數值這些概念。

變數的作用域

PHP的變數作用域與C很類似,在此不準備多說。區域性變數在所存在的函數內部有效,全域性變數作用域是檔案作用域(限於單個PHP檔案),若區域性變數同全域性變數重名,同C的處理方式,全域性的被遮蔽。

稍微麻煩一點的是,要想在函數內存取全域性變數,需使用global關鍵字宣告,否則的話PHP就認為是一個與全域性變數同名的區域性變數。

複製PHP內容到剪貼簿

PHP程式碼:

<?php
$a=1;
function func()
{
   echo "The value of a is:".$a;
}
func();
?>

以上程式碼沒有輸出1,為什麼呢?PHP把函數裡的$a看作是一個全新的區域性變數,此$a非彼$a(函數體外的全域性變數),此$a未賦值,因此輸出為空。

如果我們要想在函數體內部存取全域性變數$a的值,須在存取之前宣告一句:global $a; 這樣PHP就知道要存取的是全域性變數$a了。

還有一種方法是利用PHP的系統陣列$GLOBALS,該陣列是PHP系統自動生成和維護的,它記錄了所有全域性變數。echo $GLOBALS[「a」];即可輸出其中$a的值。

PHP的靜態變數僅在區域性函數域中存在,同C是完全相同的。

PHP有一種特殊的動態變數,名字聽起來很容易讓人認為就是C語言的普通變數(動態的、區域性的),但這個動態的含義有點特殊,它是指變數名可以動態賦予!也就是說,可以讓應用程式的終端使用者為變數指定名字!

複製PHP內容到剪貼簿

PHP程式碼:

<?php
$a="newname";
$$a="content";   //newname本是$a的值,但是$$a的含義是以$a的值為名的變數
echo $newname; //$$a等價於$newname
echo $a;
?>

運算子和表示式

PHP在運算子和表示式方面和C極其類似,有算術、邏輯、關係、位運算子及相應的表示式,也有條件運算子(:?)及其表示式,同樣還是我們開始提到的那個思想,實用為上,很多限制被取消了,相對較寬鬆。舉個例子:

複製PHP內容到剪貼簿

PHP程式碼:

<?php
$a="1";
$b=1;
if ($a==$b) echo "Equal!";
else echo "Not Euqal!";
?>

按照C的思維方式來看,$a是字元,$b是整型,兩者比較是字元的ASCII碼值與整數比較,顯然不等,而PHP執行結果卻是「Equal!」,看到這裡,是不是有點衝破封建大家庭的禮教與心上人私奔的感覺?呵呵,抑或是驚呼PHP無法無天?

接下來還有讓你目瞪口呆的,若$a="1e3"; $b=1000; 依然是「Equal!」,也就是說PHP在比較時能自動將字串「按照人的理解方式」進行轉換,1e3不就是科學計數法表示的1000嗎?甚至$a=」1e3HelloWorld」;都會相等

PHP將字串轉換為數值時會自動擷取全部它能理解為數值的部分!

其實C也允許跨越資料型別的比較,比如字元型和整型比較,C也會自動轉換型別,但它是「按照計算機的思維方式」轉換的,因為字元在計算機裡就是按照ASCII碼儲存的。

PHP的「人性化」也帶來了麻煩,當我們想嚴格比較兩個變數的時候怎麼辦呢?

於是PHP提供了一對特殊的運算子:全等(===)和非全等(!==),只有當值相當且資料型別相同時,才叫全等,兩者有一不符,則非全等。

此時,即使1與1.0也是非全等的,原因你一定知道吧。如果你覺得只有這樣才踏實,那麼恭喜你,你已經被C洗腦了。

運算子有優先順序和結合性的概念,這方面和C是類似的,你也許記不清所有的優先順序關係,但是沒關係,我們有括號呢。

流程控制

PHP的流程控制語句是與C最像的部分了,簡直可以照搬。

有兩點值得注意,一是switch case語句中case後面可以寫任意表示式,而不是C規定的只能是常數表示式,C的這種規定太不近人情了,以至於很多人學完了C還不知道case score〉90:這樣的寫法錯在哪裡。現在好了,PHP裡面,你可以這樣寫了。

再就是很奇怪的一點,if elseif else結構中間的else和if可以連在一起寫。

此外,PHP還有一個獨特的迴圈結構foreach,是專門為陣列遍歷準備的,稍後介紹。

函數

PHP使用者自定義函數的語法與C也很類似,可想而知,由於PHP弱化資料型別的概念,所以函數的返回值型別也就弱化了,函數定義的一般形式是:

function函數名($引數1,$引數2,……,$引數n)
{
  函數體
  return語句返回值
}

比C的「寬鬆」之處在於函數可以巢狀定義,但是為了一個明晰的程式碼結構,還是嚴格要求自己的好。

這裡我們再說說參照。前面提到參照其實就是給變數取個小名(專業的話叫別名),即兩個或多個變數名對應同一變數儲存空間。

這一概念用在函數引數上特別有用,我們知道實參與形參的結合是單向值傳遞,即實參將它的值複製給形參,而形參變數在函數體中可能被改變

但由於形參變數會在函數返回時被復原,所以形參不能將改變了的值傳回給實參,這是學C的人都應該十分清楚的,大家都做過那個交換兩個數的實驗。

這一機制保證了函數只能有一個返回值,當需要返回多個值的時候,我們可以使用參照做形參,這相當於把實參的地址傳遞給函數,函數對這個地址上的資料進行操作,當然就可以把改變保留下來。

參照的概念是C++裡增加的,PHP的函數也支援參照做形參。只要把C++裡參照做引數的概念理解清楚了,在PHP裡是完全一樣的。

PHP有巨大的函數庫,比如關於時間的函數就有一大堆,寫PHP程式時,當你有個功能想要實現,第一件事應該是查PHP函數手冊,看看有沒有能滿足你的要求的函數,或者是通過多個函陣列合實現也行,而不是自己動手去寫(練習程式設計技能或改進PHP者除外),記住一句老話:不要重複發明輪子。

要想掌握PHP,熟練使用常用函數是必須的,但這不是我們這篇文章的目標,有機會專題探索吧。

陣列

這回甭指望我說PHP的陣列和C差不多了,因為PHP的陣列,簡直就不是C的陣列!PHP的陣列應該叫做「集合」,不是緊急集合的集合,是數學意義上的集合,如果你學過資料結構就更明白了。

說白了,PHP的陣列就是把一堆資料(什麼型別都行)放在一起。這在C裡是很瘋狂的想法,但是在現實中是很實用的,比如一條資料庫記錄可能由整型、字串型、浮點型等不同型別的若干欄位組成,

如果能一次讀取出來放在一個「陣列」中用下標存取,是不是很方便呢?這種「陣列」,是不是很像C的結構體呢?其實它比結構體還靈活,它可以自動增減資料元素。

PHP陣列的定義是通過array函數實現的,一般形式為:

$陣列名=array(鍵名=>資料,鍵名=>資料,……, 鍵名=>資料);

這裡的鍵名在C中叫下標,C規定下標必須是整數且必須從0開始依次遞增。

在PHP裡,鍵名非常人性化,對應的資料如果儲存的是姓名,鍵名就可以叫name,是成績,就可以叫score,當然你如果想用整數也可以,隨你的便。如果你懶得在定義陣列時指定鍵名,可以這樣寫:

$陣列名=array(資料1,資料2,……, 資料n);

這時候PHP會按照C語言的方式按資料的先後順序從0開始自動賦予整型鍵名。

PHP提供了一個特別方便的顯示陣列全部元素的函數print_r

複製PHP內容到剪貼簿

PHP程式碼:
 
<?php
$arr1=array(100,200,300,400);
$arr2=array("num"=>100,"name"=>"Liuxy","score"=>98);
print_r($arr1);
echo "<br>";
print_r($arr2);
?>

以上程式碼的輸出結果如下:

Array ( [0] => 100 [1] => 200 [2] => 300 [3] => 400 )
Array ( [num] => 100 [name] => Liuxy [score] => 98 )

若要定義二維陣列,可以巢狀地使用array函數,同C類似,也是把二維陣列的每一行看作是一個一維陣列,構成每一行的一維陣列可以互不相同。如:

複製PHP內容到剪貼簿

PHP程式碼:

$arr=array(
           "row1"=>array(100,200,300,400),
           "row2"=>array("num"=>100,"name"=>"Liuxy","score"=>98)
         );

PHP陣列元素的存取同C類似,都是陣列名[鍵名]的形式。

PHP陣列的遍歷可以通過foreach語句實現,foreach語句格式如下:

foreach (陣列名as 變數名)資料元素處理語句;

翻譯成C語言就是:

for(i=0;i<n; i++){變數名=a;其他包含「變數名」的處理語句}
foreach等價於前面的for (i=0;i<n; i++)

as等價於「變數名」與a之間的等號,這下你明白了吧。

例如:

複製PHP內容到剪貼簿

PHP程式碼:

<?php
$arr=array(1,2,3,4,5,6);
foreach ($arr as $value ) echo」$value<br>」;
?>

輸出結果是什麼?想想看。

如果還想把對應的鍵名也同時輸出出來,可以用這樣的形式:

foreach ($arr as $key=>$value) echo「鍵名為$key的元素值為$value」;

在C中遍歷二維陣列我們一般用二重for迴圈,相應地,PHP中的foreach也可以巢狀使用,分析一下下面的程式你就明白了:

複製PHP內容到剪貼簿

PHP程式碼:

<?php
$arr=array(
             "row1"=>array(100,200,300,400),
             "row2"=>array("num"=>100,"name"=>"Liuxy","score"=>98)
           );
 
foreach ($arr as $key=>$value)
{
    echo "$key=>$value";
    echo "<br>";
    foreach ($value as $k=>$var) echo "$k=>$var<br>";
}
?>

PHP的陣列元素是可以動態增長的,這是C裡面不敢想的。

為陣列增加一個元素很簡單,同存取陣列元素一樣,只不過鍵名是新的或者為空,如$arr[new]=3; 或$arr[]=3,這樣做的結果是PHP為陣列$arr增加一個鍵名為new的元素其值為3,若鍵名為空,則以當前整型鍵名的最大值加1作為預設的鍵名分配給新的元素。

PHP的這種動態增長陣列有時候很方便,但也帶來隱患,比如當我們企圖修改已存在的元素值而寫錯了鍵名時,就變成了新增一個元素,而這樣的邏輯錯誤,系統是不會報錯的。

可以增長就可以縮減,要想刪除一個陣列元素,可以使用unset函數,如刪除上面新增的那個元素,可以寫成unset($arr[new])。也可以使用unset函數刪除整個陣列結構,如unset($arr),要注意這同逐個刪除全部陣列元素不同,後者還保留有陣列的結構。

形象地說,後者是人去樓空,但樓還在,前者連樓也拆除了。有意思的是刪除陣列全部元素後如果新增一個元素,它的預設鍵名將延續之前陣列的最大鍵名遞增,要想從0開始,可以使用array_values函數重置,如$arr=array_values($arr)。

提醒大家的是,PHP為陣列的排序、查詢、合併、拆分提供了大量函數,用到這些基本演算法時,不用再去翻資料結構課本了,呵呵……

這個專題主要把精力集中在PHP的基本語法上,通過與C的對比來加深理解,有很多細節問題未深入討論。學習任何東西都是一個螺旋上升的過程,我們先瀏覽一下知識脈絡,更多的需要在實踐中去體會。

下一個專題我們是不是研究一下PHP5的物件導向?你可能會說「我沒學過C++」,沒關係,這回我們不比較了,C++的物件導向概念是所有語言中最複雜的,而PHP5的物件導向由於是從實用出發所以比較簡明,你不妨先學PHP5的物件導向,理解物件導向的概念,然後再去啃C++的OOP吧。

感謝大家的閱讀,希望大家收益多多。

本文轉自: https://blog.csdn.net/ailxxiaoli/article/details/52199337

以上就是帶你深入了解php與C語言的區別的詳細內容,更多請關注TW511.COM其它相關文章!