【PHP】英文部落格專欄PHP快速入門個人筆記

Xander發表於2023-01-27

英文部落格專欄PHP快速入門

引言

​ 本文是對於英文原始部落格的一個PHP入門專欄的個人筆記摘錄,因為非常入門並且自身有JAVA語言基礎,看的比較快並且會忽略很多共同點,建議讀者有能力可以看看部落格的原文順帶提升英文能力,作者文字表達能力非常強,寫的非常棒。

​ 這篇專欄介紹了PHP8入門,專欄寫於2022年中旬,不管是單詞還是語法句式都十分通俗易懂,學技術的同時提升英語水平並且有助於提升自信心

目錄

原始部落格地址

https://thevalleyofcode.com/php/

介紹

PHP是一個兩級分化的語言,覺得它好的人稱讚它簡單,PHP的語法比較自由上手非常簡單。而不好的人則會像我一樣認為是個四不像語言,既有前端指令碼的影子,但是同時支援物件導向的方式組合程式碼,總是會有種奇怪的感覺。

但是不得不承認,世界上絕大多數WEB網站都是PHP構建的,PHP是web領域當之無愧的佼佼者。雖然這語言現在在國內是一潭死水,但是在國外它是能排進前十的熱門程式語言。

PHP在短短的幾年內快速發展,從最開始幾年的PHP4和PHP5的膨脹,到現在PHP8的版本釋出,更新迭代的速度還是很快的。

過往歷史

PHP起源於1994年的個人部落格網站,作者是rasmus lerdorf,PHP在1997到2000隨著網際網路的快速崛起並且爆炸式增長。

用途:

  • 和HTML存在一點點互動動態的HTML語言,以及web應用程式當中對外提供訪問。
  • Facebook就是構建在PHP網站之上的,早期微微博也同樣用的PHP語言
  • wiki百科同樣使用PHP構建

PHP是一個怎麼樣的語言

雖然PHP被戲稱指令碼語言,但是實際上它是解釋型語言,和廣大編譯執行的服務端語言沒什麼區別。只不過和其他大部分解釋型語言不同點是PHP不需要編譯就可以執行,或者可以認為編譯的動作本身就是自動的。這和Java,GO以及c語言等等都有很大不同。在JAVA領域PHP非常像JSP,但是實際對比會發現要比JSP更靈活和方便,也更好用。

這個語言內部可自動透過編譯器把程式碼翻譯成機器可以認識以及可以執行的語言。

從個人角度看PHP被稱作指令碼語言是比較合適的詞,因為它在web領域如魚得水。此外因為PHP是動態型別語言,開發者不需要關注變數型別,但是有時候又因為型別轉化的問題出現一些難以察覺的錯誤。

動態型別語言是高階程式語言的趨勢這一點毋庸置疑。就連JDK11也實現了 var 關鍵詞的動態型別語法糖定義就可以看出端倪。

最後用作者的原文總結:PHP是一門很像JavaScript的語言,不同的是它有動態型別,靈活型別的解釋型後端語言。

設定PHP

本部分作者介紹了mamp的安裝使用,個人沒有使用經驗就不詳細記錄了,對於PHP作者推薦使用VScode 編輯器開發,個人使用下來發現確實好用,當然Jerbrian的PHP IDE也不錯,對於常年使用IDEA的開發人員基本可以無縫銜接。

PHP 開發一般依賴套件,PHP本身就是起源於個人部落格專職於WEB Application領域,所以他需要最為根本的軟體比如Apach,MysqlRedis等等。

PHP開源套件軟體很多,這裡就不過多展開了。當然套件開發不是強制的,當然開發者開發過程中也可以單獨部署中介軟體和資料庫。

對於php的web應用,必備元件無外乎下面幾個:

  • PHP語言環境變數,推薦最新版的PHP8。
  • 資料庫,通常以MySQL為主。
  • apache或者nignix作為web伺服器。

PHP是面向http web應用程式開發語言,很多時候都需要和HTML頁面配合,這和古老的JSP語言有點類似,但是實際使用的時候更多是和模板引擎以及框架配合。

第一個PHP程式

PHP的Helloworld非常簡單,只需要在mamp或者其他PHP程式的開發軟體根目錄建立index.html的檔案即可。很多web server伺服器基本都使用index.html作為預設的訪問頁面,所以如果直接訪問localhost埠的webserver根路徑,那麼就會展示對應index.html頁面。

PHP程式碼通常以及<?php開頭以及?>結尾,中間編寫有關PHP語言程式碼即可,我們可以在index.html檔案全文替換成下面的程式碼。

<?php
echo 'World';
?>
雖然訪問的是html頁面,但是裡面的PHP程式碼卻會被識別翻譯並且執行。

基本型別

PHP是動態型別語言,定義變數方式如下:

<?php
$a = 5;
$b = '444';

?>

PHP支援下面的基礎型別:

  • bool boolean values (true/false)
  • int integer numbers (no decimals)
  • float floating-point numbers (decimals)
  • string strings
  • array arrays
  • object objects
  • null a value that means “no value assigned”

如果要知道變數的資料型別,可以使用var_dump()的方法檢查:

$age = 20;

var_dump($age);

運算子

PHP的基礎運算子:

算數操作: +, -, *, / (division), % (remainder) and ** (exponential).

賦值操作:=

比較操作:<, >, <=, >=,此外還有相等和全等操作,含義和JS的類似,相等可以型別不匹配比如 5=='5',全等型別必須一致,比如5==='5'就是false。

  • == returns true if the two operands are equal.
  • === returns true if the two operands are identical.

和比較操作相反的有!==以及!=符號。

自增操作:++和 - - 操作。

特殊符號:think new lines \n or tabs \t

拼接操作:PHP和其他語言比較大的區別,那就是類似字串拼接用的是 “.”

$fullName = $firstName . ' ' . $lastName;

字串操作

字串的操作和其他後端語言類似,下面簡單列舉部落格中的一些實驗,這裡直接上程式碼就不過多解釋了:

$name = 'Flavio';
strlen($name); //6

$name = 'Flavio';
substr($name, 3); //"vio" - start at position 3, get all the rest
substr($name, 2, 2); //"av" - start at position 2, get 2 items

$name = 'Flavio';
str_replace('avio', 'ower', $name); //"Flower"

$name = 'Flavio';
$itemObserved = str_replace('avio', 'ower', $name); //"Flower"
  • trim()") strips white space at the beginning and end of a string
  • strtoupper()") makes a string uppercase
  • strtolower()") makes a string lowercase
  • ucfirst()") makes the first character uppercase
  • strpos()") finds the firsts occurrence of a substring in the string
  • explode()") to split a string into an array
  • implode()") to join array elements in a string

編寫註釋

編寫註釋的方法如下:

// single comment
/*

this is a comment

*/

//or

/*
 *
 * this is a comment
 *
 */

//or to comment out a portion of code inside a line:

/* this is a comment */

和數字有關的內建函式

作者事先列舉一些和數字或者數學計算有關函式:

  • round()") to round a decimal number, up/down depending if the value is > 0.5 or smaller
  • ceil()") to round a a decimal number up
  • floor()") to round a decimal number down
  • rand()") generates a random integer
  • min()") finds the lowest number in the numbers passed as arguments
  • max()") finds the highest number in the numbers passed as arguments
  • is\_nan()") returns true if the number is not a number

Array陣列

陣列定義可以用方括號或者array函式,陣列可以當做其他程式語言的列表(容器)看待,不需要定義長度並且容量自動增長。

列表裡面的元素型別可以不一致,甚至元素可以是另一個列表。

// 陣列定義
$list = [];

$list = array();

// 初始化定義
$list = [1, 2];

$list = array(1, 2);

$list = ['a', 'b'];
$list[0]; //'a' --the index starts at 0
$list[1]; //'b'

$list = [1, [2, 'test']];

新增元素可以使用空方括號的方式設定值,這時候引數會自動在末尾追加。

$list = ['a', 'b'];
$list[] = 'c';

/*
$list == [
  "a",
  "b",
  "c",
]
*/

使用array\_unshift 新增元素到列表頭部:

$list = ['b', 'c'];
array_unshift($list, 'a');

/*
$list == [
  "a",
  "b",
  "c",
]
*/

使用count函式計算陣列的元素數量:

$list = ['a', 'b'];

count($list); //2

檢查元素是否在陣列,使用in\_array 函式\`:

$list = ['a', 'b'];

in_array('b', $list); //true

arrays常用函式

常用函式根據作者筆記記錄即可。

  • is_array() to check if a variable is an array
  • array_unique() to remove duplicate values from an array
  • array_search() to search a value in the array and returns the key
  • array_reverse() to reverse an array
  • array_reduce() to reduce an array to a single value using a callback function
  • array_map() to apply a callback function to each item in the array. Typically used to create a new array by modifying the values of an existing array, without altering that.
  • array_filter() to filter an array to a single value using a callback function
  • max() to get the maximum value contained in the array
  • min() to get the minimum value contained in the array
  • array_rand() to get a random item from the array
  • array_count_values() to count all the values in the array
  • implode() to turn an array into a string
  • array_pop() to remove the last item of the array and return its value
  • array_shift() same as array_pop() but removes the first item instead of the last
  • sort() to sort an array
  • rsort() to sort an array in reversing order
  • array_walk() similarly to array_map() does something for every item in the array, but in addition it can change values in the existing array

關聯陣列

到目前為止,我們已經使用了帶有增量數字索引的陣列:0、1、2... 您還可以使用帶有命名索引(鍵)的陣列,我們稱它們為關聯陣列:

$list = ['first' => 'a', 'second' => 'b'];

$list['first'] //'a'
$list['second'] //'b'

可以透過關聯陣列進行標記key以及value,關聯陣列同樣有比較多的操作方法:

  • array_key_exists() to check if a key exists in the array
  • array_keys() to get all the keys from the array
  • array_values() to get all the values from the array
  • asort() to sort an associative array by value
  • arsort() to sort an associative array in descending order by value
  • ksort() to sort an associative array by key
  • krsort() to sort an associative array in descending order by key

在此處檢視所有有關聯陣列函式: https://www.php.net/manual/en/ref.array.php

條件語句

條件語句的最基礎用法:

$age = 17;

if ($age > 18) {
  echo 'You can enter the pub';
} else {
  echo 'You cannot enter the pub';
}

這裡用了cannot而不是can't是因為單引號巢狀會出現“截斷”導致報錯,需要單引號內部巢狀需要使用轉義符\反斜槓

<, >, <=, >=, ==, === , !=, !== 這些符號在實際使用和條件語句一起使用:

這裡需要注意PHP提供了專門的 elseif,而不能像其他語言一樣使用 else[空格]if 的語法:

$age = 17;

if ($age > 20) {
  echo 'You are 20+';
} elseif ($age > 18) {
  echo 'You are 18+';
} else {
  echo 'You are <18';
}

Swtich的語法和其他程式語言是一致的:

$age = 17

switch($age) {
  case 15:
    echo 'You are 15';
    break;
  case 16:
    echo 'You are 16';
    break;
  case 17:
    echo 'You are 17';
    break;
  case 18:
    echo 'You are 18';
    break;
  default:
    echo "You are $age";
}

迴圈

PHP的迴圈語句語法有while, do while, for, and foreachwhiledo while的方法和大部分程式語言沒什麼不同。

$counter = 0;

while ($counter < 10) {
  echo $counter;
  $counter++;
}


$counter = 0;

do {
  echo $counter;
  $counter++;
} while ($counter < 10);



主要差別是foreach語法,可以用他遍歷列表,也可以用來遍歷列表獲取索引,也就遍歷關聯陣列的key/value值。

$list = ['a', 'b', 'c'];

foreach ($list as $value) {
  echo $value;
}

$list = ['a', 'b', 'c'];

foreach ($list as $key => $value) {
  echo $key;
}

對於普通for迴圈,可以使用count函式計算陣列長度的size。

$list = ['a', 'b', 'c'];

for ($i = 0; $i < count($list); $i++) {
  echo $list[$i];
}

//result: abc

和迴圈搭配使用的break和continue語法:

$list = ['a', 'b', 'c'];

for ($i = 0; $i < count($list); $i++) {
  if ($list[$i] == 'b') {
    break;
  }
  echo $list[$i];
}
// result a

$list = ['a', 'b', 'c'];

for ($i = 0; $i < count($list); $i++) {
  if ($list[$i] == 'b') {
    continue;
  }
  echo $list[$i];
}

//result: ac

函式

PHP函式的主要特點:

  • PHP的函式只支援單返回值。
  • 如果沒有返回值或者省略則接收為null,注意這裡是有陷阱的,如果呼叫一個無返回值的方法,會獲得null的結果,PHP並不會對此報錯。
  • 引數可以等號設定預設值。
  • 可以指定引數型別,也可以省略,省略會自動根據上下文猜測型別。
function sendEmail($to) {
  echo "send an email to $to";
}

sendEmail('test@test.com');

// result: send an email to test@test.com 

可以手動指定引數的型別,當然絕大多數情況下不會這樣寫(很囉嗦還浪費時間),所以看一下就可以直接忘記:

function sendEmail(string $to, string $subject, string $body) {
  //...
}

PHP函式的引數支援定義的時候指定預設值,如果呼叫方沒有傳值就使用預設值:

function sendEmail($to, $subject = 'test', $body = 'test') {
  //...
}

sendEmail('test@test.com')

帶返回值的函式定義如下,我們同樣可以手動指定函式的返回值型別:

function sendEmail($to): bool {
  return true;
}

function sendEmail($to) {
  return true;
}

$success = sendEmail('test@test.com');

if ($success) {
  echo 'email sent successfully';
} else {
  echo 'error sending the email';
}

匿名函式

PHP的匿名函式和JavaScript的寫法是類似的,使用變數接收不帶名字的function方法,由於不帶返回值的函式預設返回Null,所以可以認為匿名函式的變數就是Null。

匿名函式是支援變數傳遞的,語法是在匿名方法後面追加use括號

$test = 'test';

$myfunction = function() use ($test) {
  echo $test;
  return 'ok';
};

$myfunction()

值傳遞和地址傳遞

PHP預設情況下的引數傳遞都是值傳遞,也就是說外部的引數傳遞在函式內部出現改變是不會一併改變的,因為值傳遞是用了一份變數副本進行資料操作。

地址傳遞或者說引用傳遞需要在引數前面加取地址的符號,這裡的寫法就類似C語言的指標了。

$character = 'a';

function test(&$c) {
  $c = 'b';
}

test($character);

echo $character; //'b'

箭頭函式

PHP的箭頭函式相當於JS的函數語言程式設計,和Java的箭頭函式類似,但是箭頭函式用了等號而已。

$printTest = fn() => 'test';

$printTest(); //'test'

$multiply = fn($a, $b) => $a * $b;

$multiply(2, 4) //8

前面提到過匿名函式需要使用 use 語句接收外部引數,而箭頭函式就不需要如此定義便可以直接接收外部引數,寫法方便和簡潔易懂:

$a = 2;
$b = 4;

$multiply = fn() => $a * $b;

$multiply()

總之PHP的函式有三種定義方法,普通函式,箭頭函式和匿名函式。

使用map,reduce,filter函式迴圈陣列處理

array_map:函式可以對於每個元素呼叫回撥函式並且返回結果,最後會返回一個全新的列表。首個引數是回撥函式,其次是列表。

array_filter:函式則是對於每個元素呼叫回撥函式並且過濾掉不符合的元素,注意第一個引數是陣列,然後第二個引數是回撥函式,filter是符合函式回撥結果的可以認為是有效的。

array_reduce:函式比較特殊一些,最後有一個引數有一個初始值,函式會從初始化的值對後續的每個元素進行回撥函式合併,比如計算階乘的值就可以用這個函式。

$numbers = [1, 2, 3, 4];
$doubles = array_map(fn($value) => $value * 2, $numbers);

//$doubles is now [2, 4, 6, 8]

$numbers = [1, 2, 3, 4];
$even = array_filter($numbers, fn($value) => $value % 2 === 0)

//$even is now [2, 4]

$numbers = [1, 2, 3, 4];

$result = array_reduce($numbers, fn($carry, $value) => $carry * $value, 1)

物件導向

物件導向討論

PHP的物件導向和JAVA的比較相似,可以說大部分語法都可以通用。

如何構建物件

構建物件在PHP當中也是使用new的方式,可以透過new構建多個物件,但是物件名稱不能重複。

屬性和方法

屬性和方法常常配合使用,這裡一併介紹魔術方法構造引數。方法可以指定建構函式 __construction,其中可以新增初始化物件的行為,PHP 當中物件有很多內建函式都以 雙下劃線開頭。

class Dog {
  public $name;

  public function __construct($name) {
    $this->name = $name;
  }

  public function bark() {
    echo $this->name . ' barked!';
  }
}

$roger = new Dog('Roger');
$roger->bark();

每個類預設有一個不執行任何工作的空構造器,重寫之後如果無空建構函式,需要傳入指定引數才能初始化,否則會出現PHP的error異常。

class Dog {
  public string $name;

  public function __construct($name) {
    $this->name = $name;
  }

  public function bark() {
    echo $this->name . ' barked!';
  }
}

$roger = new Dog('Roger');
$roger->name; //'Roger'
$roger->bark(); //'Roger barked!'

// result
TypeError: Dog::__construct():
Argument #1 ($name) must be of type int,
string given on line 14

物件屬性在PHP中存在三個限定符號,可以手動指定下面三個級別:

protected

private

public

這幾個類別分別對應了繼承物件可見,私有,對外公開,和JAVA、Python語言類似,這裡就不過多擴充套件含義和更多用法案例了。

class Dog {
  public $name;
  public $age;
  public $color;
}

$roger = new Dog();

$roger->name = 'Roger';
$roger->age = 10;
$roger->color = 'gray';

var_dump($roger);

/*
object(Dog)#1 (3) {
  ["name"]=> string(5) "Roger"
  ["age"]=> int(10)
  ["color"]=> string(4) "gray"
}
*/

如果需要外部訪問,多數情況建議用get和set的方式,對於類內部的屬性首先需要定義public,其次引用需要使用this→xxx的方式,注意這個this是不能省略的,也是和JAVA差別比較大的點,而外部則為物件的變數引用設定的名稱加上→符號,比如dog→bark()

$roger = new Dog('Roger');
$roger->name; //'Roger'
$roger->bark(); //'Roger barked!'

屬性只有在public修飾符描述的情況下才能對外訪問和修改,如果為private或者protected則不行,限定符的安全訪問和Java的沒什麼區別。

方法內部的&dollar;this比較特殊,代表當前物件本身引用,和後端程式語言JAVA等類似。

繼承

PHP的物件支援繼承,具體語法如下:

class Dog extends Animal {

}

$roger = new Dog();
$roger->eat();

重寫

PHP重寫和JAVA的規則類似,所以我們按照JAVA的物件繼承理解即可:

class Animal {
  public $age;

  public function eat() {
    echo 'the animal is eating';
  }
}

class Dog extends Animal {
  public function eat() {
    echo 'the dog is eating';
  }
}

靜態

靜態方法和靜態屬性都是在屬性或者方法名稱前面加static。對於static類或者物件內部使用self來定義,引用方式為兩個冒號,比如User::getName

User::getName標識靜態變數的寫法是強制規定的,否則編譯器會報錯Undefined variable '$version'.intelephense(1008)

class Utils {
  public static $version = '1.0';
}
// 靜態常量的物件內部引用
self::$version;
// 靜態常量的外部引用
class Utils {
  public static function version() {
    return '1.0';
  }
}
Utils::version

物件比較

前面的運算子提到過雙等號和三等號有不同的含義,對於大部分情況下物件的比較=====會返回true和false,下面的例子就是很好的解釋。

class Dog {
  public $name = 'Good dog';
}

$roger = new Dog();
$syd = new Dog();

echo $roger == $syd; //true

echo $roger === $syd; //false

物件遍歷

物件遍歷通常是遍歷所有的內部屬性值,可以使用關聯迴圈的寫法,這個物件遍歷是PHP的一些語法特性,算是比較有意思的東西。

class Dog {
  public $name = 'Good dog';
  public $age = 10;
  public $color = 'gray';
}

$dog = new Dog();

foreach ($dog as $key => $value) {
  echo $key . ': ' . $value . '<br>';
}

物件克隆

PHP的clone 方法和JAVA一樣屬於淺複製,深入複製需要額外編寫一些程式碼。

class Dog {
  public $name;
}

$roger = new Dog();
$roger->name = 'Roger';

$syd = clone $roger;

魔術方法

魔術方法可以理解為PHP為了方便開發者管理物件而提供的一些”切面“,開發者可以透過重寫物件的特定方法控制行為:

class Dog {
  public $name;

  public function __clone() {
    $this->cloned = true;
  }
}

$roger = new Dog();
$roger->name = 'Roger';

$syd = clone $roger;
echo $syd->cloned;

其他的魔術方法包含:__call(), __get(), __set(), __isset(), __toString()

檔案包含

檔案包含的操作在PHP中有四種寫法:include, include_once, require, require_once.

include loads the content of another PHP file, using a relative path.

require does the same, but if there’s any error doing so, the program halts. include will only generate a warning.

“include”:使用相對路徑載入另一個PHP文件的內容。

“require”:執行相同的操作,但如果載入有任何錯誤程式將停止。注意“include”只會生成警告,require會直接丟擲異常資訊。

include_oncerequire_once在沒有_once的情況下執行與其相應函式相同的操作,但它們額外確保在程式執行期間僅包含一次檔案。

按照作者的經驗法則是經驗法則永遠不要使用包含或要求,因為您可能會載入同一個文件2次,include\_once和require\_once幫助您避免此問題。

下面介紹檔案包含的相關操作:

require_once('test.php');

//now we have access to the functions, classes
//and variables defined in the `test.php` file

require_once('../test.php');
require_once('test/test.php');
require_once('/var/www/test/file.php');

文件系統的有用常量、函式和變數

有關檔案的魔法常量:

__FILE__

還有一個和伺服器有關的全域性常量:

$_SERVER['SCRIPT_FILENAME']

除此之外其他的一些常用常量或者函式:

getcwd():內建函式
__DIR__:另一個神奇常量
將__FILE__與 dirname() 組合以獲得

當前文件夾的完整路徑:dirname(__FILE__)
使用 $_SERVER[“DOCUMENT_ROOT”]

錯誤

PHP的錯誤或者說異常資訊分為下面三類:

  • Warnings
  • Notices
  • Errors

前面兩個錯誤都是警告類似的,雖然有可能在程式執行過程中會出現問題但是不影響程式執行,而最後一個error則是會由PHP的直譯器直接返回報錯資訊。

預設情況下PHP是不展示錯誤資訊的,我們可以修改\`php.ini\`的配置進行調整。為了更快的瞭解配置檔案的位置和相關資訊,我們可以使用 phpinfo()方法和檢視:

<?php
phpinfo();
?>

原作者案例的對應的路徑為:/Applications/MAMP/bin/php/php8.1.0/conf/php.ini,預設情況下為off,意味著錯誤將不再顯示在網站中,但在這種情況下將在 MAMP(如果是別的開發腳手架則為其他的路徑) 的 logs 文件夾的php\_error.log文件中看到它們。

個人的wampServer的對應錯誤日誌資訊如下:

我們可以指定錯誤日誌重定向到特定的目錄:

; Log errors to specified file. PHP's default behavior is to leave this value
; empty.
; http://php.net/error-log
; Example:
;error_log = php_errors.log

新增錯誤資訊可以透過方法error\_log('test');處理,下面擷取框架的用法:

 /**
     * Logs user information to webserver logs.
     *
     * @param string $user   user name
     * @param string $status status message
     *
     * @return void
     */
    public static function logUser($user, $status = 'ok')
    {
        if (function_exists('apache_note')) {
            apache_note('userID', $user);
            apache_note('userStatus', $status);
        }
        /* Do not log successful authentications */
        if (! $GLOBALS['PMA_Config']->get('AuthLogSuccess') && $status == 'ok') {
            return;
        }
        $log_file = self::getLogDestination();
        if (empty($log_file)) {
            return;
        }
        $message = self::getLogMessage($user, $status);
        if ($log_file == 'syslog') {
            if (function_exists('syslog')) {
                @openlog('phpMyAdmin', LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
                @syslog(LOG_WARNING, $message);
                closelog();
            }
        } elseif ($log_file == 'php') {
            @error_log($message);
        } elseif ($log_file == 'sapi') {
            @error_log($message, 4);
        } else {
            @error_log(
                date('M d H:i:s') . ' phpmyadmin: ' . $message . "\n",
                3, $log_file
            );
        }
    }

異常

異常通常是除開程式語言語法之外的可控錯誤,PHP和JAVA一樣使用了try{...}catch(Exception $e)的方式進行處理:

try {
  //do something
} catch (Throwable $e) {
//we can do something here if an exception happens
  echo $e->getMessage();
}

實驗中我們可以使用除0的異常檢查異常資訊的列印:

echo 1 / 0;

異常處理的原則是細分不同的具體異常給出不同的提示,PHP的異常捕獲規則和JAVA一致:

try {
  echo 1 / 0;
} catch (DivisionByZeroError $e) {
  echo 'Ooops I divided by zero!';
} catch (Throwable $e) {
  echo $e->getMessage();
}

PHP同樣支援finally的寫法:

try {
  echo 1 / 0;
} catch (DivisionByZeroError $e) {
  echo 'Ooops I divided by zero!';
} catch (Throwable $e) {
  echo $e->getMessage();
} finally {
  echo ' ...done!';
}

更多異常處理可以參考下面的網站:

https://www.php.net/manual/en/reserved.exceptions.php

日期

常量和列舉

我們可以在 PHP 中使用 define() 內建函式定義常量,使用語法如下:

define('TEST', 'some value');

這種常量定義在使用的時候不需要使用&dollar;符號:

define('TEST', 'some value');

echo TEST;

define 類似 C 語言的 typeof。

其他定義常量的方法是const:

const BREED = 'Siberian Husky';

第三種定義常量的方法是定義列舉:

enum Status {
  case EATING;
  case SLEEPING;
  case RUNNING;
}

列舉常量的使用方法如下:

class Dog {
  public Status $status;
}

$dog = new Dog();

$dog->status = Status::RUNNING;

if ($dog->status == Status::SLEEPING) {
  //...
}

PHP web平臺部署

PHP 是一種伺服器端語言,通常以 2 種方式使用。

  1. 第一種方法是類似JSP一樣在HTML中嵌入PHP後端語言程式碼達到動態資料展示的效果。
  2. 第二種是PHP更像是負責生成“應用程式”的引擎,模板語言來生成HTML,並且所有內容都由我們所謂的框架管理。(推薦)

處理HTTP請求

本部分介紹了在沒有任何框架的情況下如何接收和處理HTTP請求,我們可以在webroot的路徑建立一個test.php檔案,此時如果對於腳手架配置偽靜態,可以直接透過/test訪問。

WEB應用絕大部分都是POST和GET請求,PHP提供了$_GET, $_POST and $_REQUEST 這些方法

$ _GET:對於任何請求,您可以使用 $\_ GET 物件訪問所有查詢字串資料,該物件稱為超全域性,並在我們所有的 PHP 文件中自動可用。
&dollar;\_ POST:對於 POST、PUT 和 DELETE 請求,更有可能需要以urlencoding 資料的形式釋出的資料或使用 FormData 物件,PHP 使用 $_POST 為您提供該物件。
$_REQUEST:$\_ REQUEST囊括了上面兩個魔法常量的內容。

下面的案例介紹了有關這些魔法常量的用法

 if (isset($_GET['tables'])) {
    $constrains = $GLOBALS['dbi']->getForeignKeyConstrains(
        $_REQUEST['db'],
        $_GET['tables']
    );
    $response = Response::getInstance();
    $response->addJSON('foreignKeyConstrains',$constrains);
}

使用cookies&dollar;\_SEVER 物件

$_SERVER 包含了許多非常有用的伺服器資訊,我們可以使用Phpinfo方法獲取伺服器內容:

<?php
phpinfo();
?>

下面是基本用法:

  • $_SERVER['HTTP_HOST']
  • $_SERVER['HTTP_USER_AGENT']
  • $_SERVER['SERVER_NAME']
  • $_SERVER['SERVER_ADDR']
  • $_SERVER['SERVER_PORT']
  • $_SERVER['DOCUMENT_ROOT']
  • $_SERVER['REQUEST_URI']
  • $_SERVER['SCRIPT_NAME']
  • $_SERVER['REMOTE_ADDR']

&dollar;\_GET方法的使用案例如下:

<form>
  <input type="text" name="name" />
  <input type="submit" />
</form>

<?php
if (isset($_GET['name'])) {
  echo '<p>The name is ' . $_GET['name'];
}
?>

&dollar;\_POST方法的使用案例如下:

<form **method="POST"**>
  <input type="text" name="name" />
  <input type="submit" />
</form>

<?php
if (isset($_POST['name'])) {
  echo '<p>The name is ' . $_POST['name'];
}
?>

這些內容直接使用的情況比較少,通常在框架中可以看到類似的引用。

使用cookies

PHP透過$_COOKIE變數可以獲取到所有和Cookie有關的資訊。

if (isset($_COOKIE['name'])) {
  $name = $_COOKIE['name'];
}

setcookie() 方法可以設定cookie資訊,我們可以新增第三個引數來說明 cookie 何時過期。如果省略,Cookie 將在會話結束時/瀏覽器關閉時過期。

setcookie('name', 'Flavio');

比如下面的程式碼可以設定7天之後過期:

setcookie('name', 'Flavio', time() + 3600 * 24 * 7);

我們只能在 Cookie 中儲存有限數量的資料,使用者在清除瀏覽器資料時可以在客戶端清除 Cookie。下面是Cookie使用的一些簡單例子:

<?php
if (isset($_POST['name'])) {
  setcookie('name', $_POST['name']);
}
if (isset($_POST['name'])) {
  echo '<p>Hello ' . $_POST['name'];
} else {
  if (isset($_COOKIE['name'])) {
    echo '<p>Hello ' . $_COOKIE['name'];
  }
}
?>

<form method="POST">
  <input type="text" name="name" />
  <input type="submit" />
</form>

Sessions

Cookie 的一個非常有趣的用例是基於 cookie 的會話。

<?php
session_start();
?>

你會發現訪問對應檔案之後,你將會看到一個新cookie名稱(PHPSESSID)被定義。這個ID就是我們常說的session ID

image-20230123212351539

與我們使用 cookie 的方式類似,我們現在可以使用 $_SESSION 來儲存使用者傳送的資訊,但這次它不儲存在客戶端。只有PHPSESSID會被儲存到客戶端。

<?php
session_start();

if (isset($_POST['name'])) {
  $_SESSION['name'] = $_POST['name'];
}
if (isset($_POST['name'])) {
  echo '<p>Hello ' . $_POST['name'];
} else {
  if (isset($_SESSION['name'])) {
    echo '<p>Hello ' . $_SESSION['name'];
  }
}
?>

<form method="POST">
  <input type="text" name="name" />
  <input type="submit" />
</form>

image-20230123212507500

可以使用session_unset()方法刪除Session當中的資訊,如果需要移除session的cookie資訊,可以使用下面的方法:

setcookie(session_name(), '');

IO

PHP服務端訪問可以使用下面的方法:

檔案是否存在file_exists()

file_exists('test.txt') //true

檔案大小獲取:

filesize('test.txt')

PHP的檔案讀寫使用同一個方法,不同的是提供訪問引數使用了 讀模式和寫模式:

$file = fopen('test.txt', 'r')

上面的方法為只讀模式,同時提供描述資訊作為返回值。我們可以呼叫 fclose($fd) 終止檔案讀寫。

下面是把檔案內容讀取到變數的方法,這裡吐槽一下使用要比JAVA的套版程式碼簡單很多,也比較符合新生高階程式語言的設計思路。

$file = fopen('test.txt', 'r')

fread($file, filesize('test.txt'));

//or

while (!feof($file)) {
    $data .= fgets($file, 5000);
}
注意:feof() 檢查我們是否尚未到達文件末尾,因為 fgets 一次讀取 5000 位元組

逐行掃描檔案套版程式碼:

$file = fopen('test.txt', 'r')

while(!feof($file)) {
  $line = fgets($file);
  //do something
}

要寫入檔案,必須一開始開啟檔案的時候指定寫入模式,同時配合fwrite函式以及fclose形成完整的檔案讀寫。

$data = 'test';
$file = fopen('test.txt', 'w')
fwrite($file, $data);
fclose($file);

刪除檔案的方法如下:

unlink('test.txt')

更多檔案讀寫方法參考:https://www.php.net/manual/en/ref.filesystem.php

database

所有後端語言必備的東西,這裡列舉了幾個常用的database:

絕大多數情況如果你需要一個資料庫,你應該使用框架或ORM,這將節省SQL隱碼攻擊的安全問題,比如比較常見的Laravel’s Eloquent 框架。

JSON

JSON 是一種可移植的資料格式,我們用於表示資料並將資料從客戶端傳送到伺服器。PHP提供了下面兩個常用方法來實現JSON字串和物件之間的轉化:

  • json_encode() to encode a variable into JSON
  • json_decode() to decode a JSON string into a data type (object, array…)

下面是一些簡單使用例子:

$test = ['a', 'b', 'c'];

$encoded = json_encode($test); // "["a","b","c"]" (a string)

$decoded = json_decode($encoded); // [ "a", "b", "c" ] (an array)

email

傳送郵件可以使用下面的方法:

mail('test@test.com', 'this subject', 'the body');

https://github.com/PHPMailer/PHPMailer 提供了更多有郵件相關的實用API。

部署PHP應用Composer

Composer類似NodeJS的 NPM,和大部分的一站式依賴管理是類似的。Composer安裝之後的頁面內容如下:

可以使用composer require nesbot/carbon 命令對於專案進行依賴匯入。正確匯入之後會出現composer.json以及composer.lock檔案,composer.lock檔案可以對於依賴版本進行鎖定。

{
    "require": {
        "nesbot/carbon": "^2.58"
    }
}

當對應目錄引入依賴之後,在PHP檔案當中可以使用下面的用法:

<?php
require 'vendor/autoload.php';

use Carbon\Carbon;

echo Carbon::now();

最終訪問對應頁面的展示內容如下:

“require 'vendor/autoload.php';”行作用是啟用自動載入。這裡順帶提一下還記得我們談論require\_once()和include\_once()嗎?我們不需要手動搜尋要包含的文件,我們只需使用 use 關鍵字將庫匯入我們的程式碼即可。

部署PHP應用

最後作者寫了一篇從零開始搭建GIT的文章比較有意思,本部分內容建議結合一些框架專案學習,部落格提到的內容比較入門這裡就不記錄了。

See how to setup Git and GitHub from zero

寫在最後

更多的當作英文學習資料看待,順帶能學到一些技術內容,挺不錯的。

相關文章