準備
下載 PHP
純粹想練習寫寫動態網頁程式的話,可到 PHP 官方網站 下載程式引擎,不用搭配 Apache HTTP Server 就能跑 PHP 程式。
想架站跑 PHP 程式的話,為免除設定的麻煩,建議下載整合包,一次安裝全都搞定!例如 Apache + MariaDB + PHP + Perl 的 XAMPP。
本文示範的程式就是練習用,所以直接拿 PHP 程式引擎來跑。
Hello, world!
PHP 除了與各 HTTP Server 軟體搭配使用,也可單獨當解譯器使用,為作業系統寫腳本跑程式。
用文字編輯器,輸入如下程式碼,並儲存為 main.php:
進入命令提示字元,然後用 PHP 資料夾裡面的 php.exe 執行 main.php,沒問題的話會顯示 Hello, world!:
Run with built-in web server
php.exe 內建網頁伺服器的功能,切換到存放網頁的目錄,輸入:
這樣就能用網頁瀏覽器,輸入 http://127.0.0.1 連上網頁。
要開放區域網路或網際網路連線的話,則須輸入你電腦分配到的 IP 位址。
覺得切換到網頁所在目錄麻煩的話,可以用 -t 參數指定存放網頁的目錄。
預設網頁為 index.php 或 index.html,也就是這兩個網頁名稱不用輸入,PHP 網頁伺服器也能連。
Run as interactive shell
php.exe 也有 Shell 模式可用,提供直接以 PHP 語言寫程式的環境:
很 Perl 的 C 語言
PHP 結合 C++ 和 Perl 兩種語言的語法,基本上採用的是 C 語言手法在寫程式,然後加上 Perl 的動態型別資料簡化 C 語言的工作,所以沒有帶來學習和使用上的負擔,反而更易學易用。而 C++ 的物件導向只是一種輔助語法,團隊開發大型專案時可以用到,用不到時放著不用管它,絲毫不影響你 PHP 的寫作方式。PHP 是多麼清爽的程式語言啊!
總之,大致上會寫 C 程式就會 PHP,所以底下只挑出 Perl 和 C++ 的部分,為 C 語言做補充說明,來介紹 PHP 語法,而不是完整說明。
完整教學,已經有 W3Schools 的《PHP 7 Tutorial》,或「菜鸟教程」翻譯成中文的《PHP 教程》,簡單明瞭、條目詳盡,應該沒人可以寫得比這網站好。
若要取得更詳盡的操作指南,還有官方文件《PHP 手册》,入門者建議從《语言参考》閱讀學習。這官方說明文件不但提供中文翻譯,而且還能下載閱讀,非常實用!
原始碼基本架構
PHP 程式碼寫在如下符號裡面:
<?php
?>
你可以把多個這樣的 PHP 程式碼,隨意插在 HTML 裡面。
不與 HTML 混用的話,可以省略 ?> 結尾符號。
<?php echo 資料?> 可以寫成 <?=資料?>。
還有其它風格的符號可用,像是 ASP 風格(<%%>)、HTML 風格(SCRIPT 標籤),有興趣的自行搜尋資料吧~
分號與敘述
PHP 的 ; 並不是一段敘述的結尾,而是將不同段的敘述分隔開來。
因此,若程式只有一道敘述,其實不用加 ; 也能執行。但有多個敘述,就要用 ; 分隔,且最後一個敘述可以不加。
但每段敘述都加 ; 並不會報錯,且大家都這麼寫、也都誤以為 PHP 每行程式要加分號表示結束,所以關於 ; 的事,知道一下就好,不用真的省略~
將錯就錯,有時候是好事。
變數
以 $ 開頭的識別名稱為變數,不須指定資料型態,由 PHP 自動根據資料配置型別。
大小寫不同,視為不同變數名稱。(但 PHP 的指令和函式不分大小寫。)
在變數前面使用 global 指令,可宣告為全域變數。
資料型態
PHP 有 string、integer、float、boolean、array、object、null 等型態的資料,由程式引擎自動根據資料配置型態,不需個別宣告。
想強制限定資料型態的話,使用 declare(strict_types=1),就能以 array、bool、callable、float、int、interfaces、string 宣告型態。
轉型可使用 C 語言的 (型別) 語法,或 setType(變數, 型別) 函式。
布林值使用 TRUE 和 FALSE,且保留 C 語言非 0 即 true 的設計。
常數
必須呼叫 define('常數', '資料') 函式定義常數,資料可為陣列的型式。
常數一律全域範疇。
常數不用加上 $ 符號,因此為了容易辨識常數,避免與關鍵字或函式混淆,建議全大寫。
可用 defined(常數) 檢查常數是否已定義。
內定常數(Core predefined constants)
| string | DEFAULT_INCLUDE_PATH | PHP 載入程式時會尋找的目錄
|
| 32767 | E_ALL | 所有的錯誤和警報(正式上線用)
|
| 64 | E_COMPILE_ERROR | 編譯時發生錯誤
|
| 128 | E_COMPILE_WARNING | 編譯時發出警報
|
| 16 | E_CORE_ERROR | PHP 初始啟動時發生錯誤
|
| 32 | E_CORE_WARNING | PHP 初始啟動時發出警報
|
| 8192 | E_DEPRECATED | 執行期用了將列為警報的功能
|
| 1 | E_ERROR | 執行期發生錯誤
|
| 8 | E_NOTICE | 執行期用了將列為錯誤的功能
|
| 4 | E_PARSE | 編譯時剖析發生錯誤
|
| 4096 | E_RECOVERABLE_ERROR | 發生可捕獲的錯誤
|
| 2048 | E_STRICT | 更多所有的錯誤和警報(開發測試用)
|
| 256 | E_USER_ERROR | 使用者造成錯誤
|
| 512 | E_USER_WARNING | 使用者造成警報
|
| 1024 | E_USER_NOTICE | 使用者用了將列為錯誤的功能
|
| 16384 | E_USER_DEPRECATED | 使用者用了將列為警報的功能
|
| 2 | E_WARNING | 執行期發出警報
|
| boolean | FALSE | Boolean 資料型態的假值
|
| null | NULL | Null 資料型態的值
|
| string | PEAR_EXTENSION_DIR | PEAR 套件目錄位置
|
| string | PEAR_INSTALL_DIR | PEAR 安裝目錄位置
|
| string | PHP_BINARY | PHP 執行檔的完整路徑和檔名
|
| string | PHP_BINDIR | PHP 的 bin(執行檔)目錄存放位置
|
| string | PHP_CONFIG_FILE_PATH | php.ini 的路徑
|
| string | PHP_CONFIG_FILE_SCAN_DIR | php.ini 可掃描的目錄
|
| string | PHP_DATADIR | PHP 的 data(資料)目錄存放位置
|
| integer | PHP_DEBUG | 用來判斷除錯模式是否啟用
|
| string | PHP_EOL | 換行(End Of Line)
|
| string | PHP_EXTENSION_DIR | PHP 存放套件的目錄位置
|
| string | PHP_EXTRA_VERSION | PHP 版號中的延伸名稱
|
| string | PHP_FD_SETSIZE | 最多能選擇多少檔案數量
|
| integer | PHP_FLOAT_DIG | 小數位數.
|
| float | PHP_FLOAT_EPSILON | 科學記號最小值
|
| float | PHP_FLOAT_MAX | 小數最大範圍
|
| float | PHP_FLOAT_MIN | 小數最小範圍
|
| integer | PHP_INT_MAX | 整數最大範圍
|
| integer | PHP_INT_MIN | 整數最小範圍
|
| integer | PHP_INT_SIZE | 整數位元組
|
| string | PHP_LIBDIR | PHP 的 lib(程式庫)目錄存放位置
|
| string | PHP_LOCALSTATEDIR | PHP 在客端電腦留下資料的目錄
|
| integer | PHP_MAJOR_VERSION | PHP 的主要版號。
|
| string | PHP_MANDIR | PHP 的 man(手冊)目錄存放位置
|
| integer | PHP_MAXPATHLEN | 檔案名稱最長可用多少字元
|
| integer | PHP_MINOR_VERSION | PHP 的次要版號。
|
| string | PHP_OS | 作業系統種類(例如 WINNT)
|
| string | PHP_OS_FAMILY | 作業系統名稱(例如 Windows)
|
| string | PHP_PREFIX | prefix 參數
|
| integer | PHP_RELEASE_VERSION | PHP 的更新版號。
|
| string | PHP_SAPI | cli-server 或 cli
|
| string | PHP_SHLIB_SUFFIX | 動態程式庫的附檔名(例如 dll)
|
| string | PHP_SYSCONFDIR | PHP 在客端系統讀取設定的目錄
|
| string | PHP_VERSION | PHP 的主要、次要、更新三個版號
|
| integer | PHP_VERSION_ID | PHP 版號以五個位數的整數
|
| integer | PHP_ZTS | 判斷 Zend Thread Safety 是否啟用
|
| boolean | TRUE | Boolean 資料型態的真值
|
| integer | __COMPILER_HALT_OFFSET__ | 搭配 __halt_compiler() 時用
|
魔術常數(Magic constants)
| string | __CLASS__ | 類別名稱
|
| string | __DIR__ | 目前檔案的目錄
|
| string | __FILE__ | 目前檔案的完整路徑和檔名
|
| string | __FUNCTION__ | 目前的函式名稱或匿名函式的閉包
|
| string | __LINE__ | 目前檔案的行數
|
| string | __METHOD__ | 目前的方法名稱
|
| string | __NAMESPACE__ | 目前的命名空間
|
| string | __TRAIT__ | 目前的靜態方法名稱
|
陣列
串列:
$陣列名稱 = array(值, 值, ...)
雜湊表:
$陣列名稱 = array('鍵'=>值, ...)
陣列解構式:
$串列 = [值, 值, ...]
$雜湊表 = ['鍵'=>值, ...]
陣列解構式是相當實用的語法功能,如果你想交換兩個變數的資料,只要這樣寫:
迭代
對於陣列,PHP 提供指令方便我們迭代資料:
foreach ($陣列 as $變數) {
程式;
}
foreach ($陣列 as $變數=>$變數) {
程式;
}
比必須用 reset() 讓迭代器歸零的 each() 函式方便多了~
字串
除了雙引號,也可以用 ' 單引號表示字串資料。但兩者仍有差異,例如雙引號字串能正常轉換跳脫字元,單引號字串會把倒斜線視為一般字元來顯示(\\ 和 \' 除外):
多行字串
PHP 提供 UNIX Shell 的 Here document 功能,適合表現多行字串:
$變數 = <<<標記
字串
字串
字串
標記;
標記裡面的資料,空白和換行會如實呈現,所以裡面的字串就別跟著程式碼縮排了。
字串裡的變數會直接顯示資料,不想這樣的話,可在第一個標記前後加上單引號:
$變數 = <<<'標記'
字串
標記;
運算子
跟 JavaScript 一樣,除了 == 和 !=,還提供型別檢查的 === 和 !==。
變數 ?? 值 會檢查變數是否為 NULL,是的話會賦值給變數,相當於「isset(變數) ? 變數 : 值」的寫法。
<=> 用來比較兩個值,小於的話傳回 -1,等於的話傳回 0,大於的話傳回 1。
流程控制
除了傳統用大括號 {} 的寫法,還允許用冒號的寫法:
if (判斷式):
程式;
elseif (判斷式):
程式;
else:
程式;
endif;
switch (判斷式):
case 值:
程式;
default:
程式;
endswitch;
while (條件式):
程式;
endwhile;
for (;;):
程式;
endfor;
if 只能有一個 else,要判斷多個條件,使用 elseif 指令。如果用 C 語言的習慣,會變成巢狀 if 結構,而不是多重條件分支。
函式
函式的基本結構如下:
function 函式名稱($參數 = 預設值, $參數) {
return 傳回值;
}
函式名稱不分大小寫,因此 fa()、Fa()、FA() 視為同一函式。但參數同變數,區分大小寫。
也可以不寫參數,改用內建函式處理參數:
function 函式名稱() {
func_get_arg(第幾個引數);
}
或用 func_get_args() 將引數以陣列傳回,放在變數使用。func_num_args() 則可用來取得引數的數量。
不定參數可用 ... 表示。
函式的參數為傳值呼叫,在參數前面使用 & 符號,表示傳址呼叫。
函式裡面的區域變數,可用 static 指令,宣告為靜態變數,即使函式執行完仍保留下來。
呼叫函式不能像 Perl 那樣省略括號。
匿名函式
PHP 支援匿名函式,因此可寫出立即函式:
發布函式
每執行幾次程式,就觸發一次函式:
構詞
PHP 有一種長得像函式,用起來卻像指令一樣執行效率高、有些還可省略括號的東西,叫做 language construct,表示構成語言的要素。有:
| array | array() | 建立陣列
|
| void | die([狀態值或訊息文字]) | 結束程式的執行
|
| void | echo(字串, ...) | 輸出一或多個字串
|
| boolean | empty(變數) | 檢查變數是否為空
|
| mixed | eval(字串) | 執行寫成字串的 PHP 程式碼
|
| void | exit([狀態值或訊息文字]) | die() 的別名
|
| integer | include(檔案) | 載入外部程式碼檔案(載入失敗仍會繼續執行)
|
| integer | include_once(檔案) | 載入外部程式碼檔案且不重複載入
|
| boolean | isset(變數, ...) | 檢查變數是否已設值
|
| array | list(變數, ...) | 將陣列的資料分拆到多個變數
|
| integer | require(檔案) | 請求外部程式碼檔案(請求失敗會報錯並終止執行)
|
| integer | require_once(檔案) | 請求外部程式碼檔案且不重複請求
|
| void | unset(變數, ...) | 解除變數
|
基本上這是種已經最佳化編譯好的函式,不像函式需要直譯後執行,因此性能極高,甚至比指令還高。
命名空間
用 namespace 設定命名空間,並以 use 使用命名空間。
錯誤訊息
程式敘述前面使用 @ 可以忽略錯誤訊息。
執行式
以一對 ` 括住的字串,會以作業系統的指令模式執行。
例如 `ver`,等於在 Windows 的命令提示字元執行 ver 指令,顯示作業系統的版本。
組態
可透過 php.ini 設定 PHP 程式語言環境的功能。
物件導向
PHP 4 時就有簡單的物件導向功能,雖然只有類別和繼承,但對弱型別的表述語言來說其實也夠用了。只是當時 Java 語言稱霸程式設計,誰沒跟上它的物件導向機制,就像沒辦法打造走在時代尖端技術的程式碼一樣,使用者強逼 PHP 5 照抄了一套來用。
在 PHP 5 推出的 2004 年,我完全無法想像 Java 語言的物件導向,在十年後反而是種落後時代的技術表現。隨著函數式程式設計興起,人們漸漸接觸動態型別的表述語言,發現其實都處理得很好,利大於弊,於是開始對強型別感到厭煩。Java 走在時代尖端的那套技術,如今被視為沒有寫作效率的程式寫法了~
時代確實不一樣了!如果從頭到尾都用同一個程式語言開發專案,你確實離不開 Java 語言那樣的物件導向功能,來管理終將變得巨大無比的程式碼。但現在開發的專案,比較常見的是發揮不同程式語言的特性來解決問題,因此接觸到的是各種語言寫成的小而美程式,確實用不到那套物件導向業界標準了!
現在欠缺的是新一套開發標準,如何更有效率地將開放原始碼倉庫中用不同語言做好的解決方案,結合起來完成想要的專案⋯將在 2020 年代有重大轉變。
類別
類別的語法有:
class 類別名稱 extends 父類別{
const 常數 = 初始值;
var $屬性 = 初始值;
function 方法($參數) {
程式;
}
function __construct() {
建構式;
}
function __destruct() {
解構式;
}
function __set() {
設定不存在的屬性時執行程式;
}
function __get() {
取出不存在的屬性時執行程式;
}
function __call() {
呼叫不存在的方法時執行程式;
}
}
var 可改用 public、private、protected 限制存取範疇,方法前面也可加上去。
類別的屬性和方法可用 static 宣告為靜態,在不建立物件的情況下以 類別名稱::屬性或方法 方式存取。
方法可用 final 禁止覆寫。
可用 $this 表示物件自己,但無法存取 static 屬性和方法,因為這不是物件的一部分,而是類別的。因此 PHP 5 後,新增 self 表示類別自己,以及 parent 表示父類別。
物件
$物件名稱 = new 類別名稱();
$物件名稱->屬性或方法;
複製物件使用 clone 指令。
抽象和介面
可用 abstract 和 interface 設計抽象和介面。
自動載入
PHP 沒有 package 的設計,因此外部類別是用 require 一個個載入的,沒有 import php.util.* 這類一次載入所有類別的寫法。變通的方式,就是覆寫 __autoload(),當 PHP 引擎找不到類別時,自動執行裡面的程式。
function __autoload($class) {
require_once("存放類別的目錄/$class.php");
}
這項功能將廢棄,改用 spl_autoload_register() 代替。
例外處理
try、catch、throw⋯在 PHP 可有可無,就不介紹了。
相關函式
| boolean | class_exists(類別) | 檢查是否定義了類別
|
| array | get_declared_classes() | 取得已定義的所有類別
|
| array | method_exists(物件, 方法) | 檢查物件是否擁有方法
|
| array | get_class_vars(類別) | 取得類別所有屬性
|
| array | get_class_methods(類別) | 取得類別所有方法
|
| array | get_object_vars(物件) | 取得物件所有屬性
|
| boolean | is_a(物件, 類別) | 檢查物件是否為類別的實體
|
| boolean | is_subclass_of(物件, 父類別) | 檢查物件是否為父類別的子類別
|
| string | get_class(物件) | 查詢物件是哪個類別
|
| string | get_parent_class(物件) | 查詢物件的父類別
|
| string | serialize(物件) | 將物件轉為字串(序列化物件)
|
| mixed | unserialize(字串) | 轉序列化字串為物件
|
動態網頁程式設計
伺服端程式設計是 PHP 的強項!程式庫幾乎都是繞著 HTTP Server 設計的,連 Web Service 都能兩三行搞定,就知道拿 PHP 設計網頁伺服器有多好用了。
標頭
寫 PHP 動態網頁時,經常使用如下函式設定標頭,例如文件的字元編碼:
header('Content-Type: text/plain; charset: utf-8');
傳送網頁資料
使用 HTML 的 FORM 系列元件送出填表資料,然後用 $_GET['元件名稱'] 或 $_POST['元件名稱'] 接收。
不確定送出的資料是哪一種方式,可根據 $_SERVER['REQUEST_METHOD'] 是 'GET' 還是 'POST' 來設計。
若上傳的資料包含檔案,則用 $_FILES 處理。
暫時保存跨頁資料
這是一種暫時保存共用資料,當瀏覽結束就自動釋放資料,不會在使用者電腦留下紀錄的設計,適合用來跨頁傳遞資料。
先用 session_start() 啟動暫存功能,就能以 $_SESSION['識別名稱'] 跨頁存取資料。完成工作後,使用 session_destroy() 清除資料。
長期保存網站資料
Cookie 是瀏覽器提供長期保存資料的功能,透過 JavaScript 就能寫入和讀取。
PHP 有自己更易用的實作方式,寫入用 setcookie('識別名稱', '資料', 期限),讀取用 $_COOKIE['識別名稱']:
刪除 Cookie 的方式,則是把資料清空,或把期限設為過期:
Cookie 也可做為跨頁傳遞資料的技術,尤其寫入資料時,省略第三個參數,用起來就類似 Session,在關閉瀏覽器時失效。缺點是有可能在使用者電腦留下「空資料」的紀錄,但優點是不像 Session 把資料放在伺服器增加負擔。
環境變數
$_ENV 可用來取得作業系統的環境變數,像是 $_ENV['OS'] 傳回作業系統、$_ENV['USERNAME'] 傳回使用者名稱、$_ENV['HOMEPATH'] 傳回使用者家目錄。
伺服器資訊
$_SERVER 可用來取得系統的資訊,隨不同伺服器系統,會有不一樣的情況,不清楚時,可先用 print_r() 全列出來。常用到的資訊有:
$_SERVER['HTTP_ACCEPT']
$_SERVER['HTTP_ACCEPT_CHARSET']
$_SERVER['HTTP_ACCEPT_ENCODING']
$_SERVER['HTTP_ACCEPT_LANGUAGE']
$_SERVER['HTTP_CONNECTION']
$_SERVER['HTTP_HOST']
$_SERVER['HTTP_REFERER']
$_SERVER['HTTP_USER_AGENT']
$_SERVER['PHP_SELF']
$_SERVER['QUERY_STRING']
$_SERVER['REMOTE_ADDR']
$_SERVER['REMOTE_HOST']
$_SERVER['REQUEST_METHOD']
$_SERVER['REQUEST_URI']
$_SERVER['REMOTE_PORT']
$_SERVER['SERVER_ADMIN']
$_SERVER['SERVER_NAME']
$_SERVER['SERVER_PORT']
$_SERVER['SERVER_PROTOCOL']
$_SERVER['SERVER_SIGNATURE']
$_SERVER['SERVER_SOFTWARE']
相關函式
| integer | ignore_user_abort(布林) | 與客端斷線時是否終止程式繼續執行
|
| mixed | get_browser() | 取得瀏覽器的訊息
|
| mixed | highlight_file(檔案) | 以色彩標示程式檔
|
| mixed | highlight_string(字串) | 以色彩標示程式碼
|
| string | htmlentities(字串) | 將字串中的 & ' " < > 轉為 HTML 實體
|
| string | rawurlencode(字串) | 將字串中的白字元換成 URI 編碼
|
| string | rawurldecode(字串) | 恢復字串中的 URI 編碼
|
| string | urlencode(字串) | 將字串編碼為 URI 字元
|
| string | urldecode(字串) | 將 URI 字元解碼為字串
|
| string | addslashes(字串) | 將字串中的 ' " \ NULL 換成跳脫字元
|
| string | stripslashes(字串) | 恢復字串中的跳脫字元
|
| mixed | parse_url(字串) | 拆解 URL 字串為 scheme、user、password、host、port、path、query、fragment 等部分
|
範例集
list 構詞
將陣列的資料分拆到多個變數:
但 list() 的功能,可用陣列解構式完成:
preg_match(), preg_replace(), preg_split()
INI
只內建讀取的函式,沒有寫入。
sample.ini
user = Twideem Civs
email = twideem@outlook.com
main.php
XML
SimpleXML 可以用來讀取、編輯、儲存 XML 資料,但不能新增元素和屬性。想新增的話,要改用像腳綁著鐵球闖複雜迷宮一樣難度的 DOM。
讀取 XML 檔案
sample.xml
Twideem Civs
twideem@outlook.com
main.php
user, PHP_EOL,
$xml->email;
儲存 XML 檔
User
user@e.mail
');
$xml->user = 'Twideem Civs';
$xml->email = 'twideem@outlook.com';
$xml->saveXML('sample.xml');
存取 XML 元素
sample.xml
Twideem Civs
Raideem Toukin
main.php
users->user[0], PHP_EOL,
$xml->users->user[0]['email'], PHP_EOL,
$xml->users->user[1], PHP_EOL,
$xml->users->user[1]['email'];
一個子元素時,用 -> 存取。
多個同名子元素時,用 [索引編號] 存取,或 children() 傳回陣列存取。
屬性用 [屬性名稱] 存取,或 attributes() 傳回陣列存取。
DOM
DOM 是相當難用的 API,不過底下範例化繁為簡,只用到部分功能,能「存、取、增、刪」就好。詳盡功能,請參考 PHP 官方文件《Document Object Model》。
載入 XML 文件並讀取元素和屬性
document.xml
Header
Paragraph 1
Paragraph 2
Paragraph 3
main.php
load('document.xml');
# Get a element content by name
echo $dom->getElementsByTagName('h1')[0]->textContent, PHP_EOL;
# Get a attribute value by name
echo $dom->getElementsByTagName('img')[0]->getAttribute('src'), PHP_EOL,
$dom->getElementsByTagName('img')[0]->getAttribute('width'), PHP_EOL,
$dom->getElementsByTagName('img')[0]->getAttribute('alt'), PHP_EOL;
# Get all elements name and value
$nodes = $dom->childNodes;
foreach ($nodes as $node)
echo $node->nodeName, '=', $node->nodeValue, PHP_EOL;
# Get all attributes name and value
$attributes = $dom->getElementsByTagName('img')[0]->attributes;
foreach ($attributes as $attribute)
echo $attribute->name, '=', $attribute->value, PHP_EOL;
載入 XML 文件並修改元素和屬性
main.php
load('document.xml');
# Set element content
$elements = $dom->getElementsByTagName('p');
$elements[0]->textContent = 'AAA';
$elements[1]->textContent = 'BBB';
$elements[2]->textContent = 'CCC';
# Set attribute value
$dom->getElementsByTagName('img')[0]->setAttribute('src', 'picture.jpg');
$dom->getElementsByTagName('img')[0]->setAttribute('width', '320');
$dom->getElementsByTagName('img')[0]->setAttribute('alt', '相片');
# Save XML document
$dom->save('backup.xml');
建立空白 XML 文件並新增元素和屬性
createElement('root');
$dom->appendChild($root);
# Create element and attribute
$element = $dom->createElement('element');
$element->nodeValue = 'content';
$element->setAttribute('attribute', 'value');
$root->appendChild($element);
# Save XML document
$dom->formatOutput = TRUE;
$dom->save('new.xml');
載入 XML 文件並移除元素和屬性
你可能會疑惑,DOM 為何被嫌得臭頭?看完這一節範例,你就知道原因了⋯
main.php
load('document.xml');
# Remove element
$element = $dom->getElementsByTagName('p')[0];
$element->parentNode->removeChild($element);
# Remove content
$element = $dom->getElementsByTagName('p')[1];
$element->removeChild($element->childNodes[0]);
# Remove attribute
$element = $dom->getElementsByTagName('img')[0];
$element->removeAttribute('width');
# Save XML document
$dom->save('other.xml');
首先看刪除元素,做法是先取得要刪除的元素,再從它的父元素呼叫 removeChild() 去刪除子元素。然後看刪除內容,做法是取得元素後,呼叫 removeChild() 刪除自己的第一個子元素;前提是這個元素的第一個子元素是內容結點,如果是包含各種類型的節點,請逐一檢查 nodeType 屬性是不是 XML_TEXT_NODE。刪除屬性呢?取得元素後,呼叫 removeAttribute() 刪除屬性。而且從範例輸出的 other.xml 來看,移除 P 元素後,仍留下一種叫文字節點的東西需要刪除。
可以看到,元素、內容、屬性的刪除方式,竟然都不一樣。而且刪除時可能還得一個一個檢查結點的種類,對了再刪。不然就是反過來,刪完後恐怕還得再刪其它種類的節點,才是你想要的結果~
DOM 真是了不起的發明!常用 DOM 就像多玩益智遊戲一樣,能促進腦力激盪,集中注意力,防止癡呆⋯我並不討厭 DOM 的設計,反而很喜歡就 DOM 的規則,玩一場又一場的益智遊戲,跟魔術方塊一樣有趣。
XPath
XPath 可簡化 DOM 取得節點的工作,甚至可以篩選資料。
下面範例為三井寿射進三分球,所以添加到他的得分紀錄中。
main.php
load('湘北高等学校.xml');
# 產生 XPath
$xpath = new DOMXPath($dom);
# 尋找 NodeList
$elements = $xpath->query('//player[@name="三井寿"]');
# 取出 Attribute
$value = (int)$elements[0]->getAttribute('points');
$value += 3;
# 修改 Attribute
$elements[0]->setAttribute('points', $value);
# 輸出 Attribute
echo $elements[0]->getAttribute('points');
SimpleXML 產生的物件,本身自帶 xpath() 方法,將 XPath 語法傳進參數,會傳回 SimpleXMLElement 的陣列。
更詳盡 XPath 操作方式,請參考「菜鸟教程」的《XPath 语法》。
JSON
'Twideem Civs', 'email'=>'twideem@outlook.com');
echo json_encode($array1, JSON_UNESCAPED_UNICODE), PHP_EOL;
# JSON to Array
$json2 = '{"name":"Twideem Civs","email":"twideem@outlook.com"}';
$array2 = json_decode($json2, TRUE);
echo $array2['name'], PHP_EOL,
$array2['email'], PHP_EOL;
# Object to JSON
class Password{
public $password = 'abc123';
}
$object3 = new Password();
echo json_encode($object3), PHP_EOL;
# JSON to Object
$json4 = '{"password":"abc123"}';
$object4 = json_decode($json4);
echo $object4->password;
既然 PHP 內嵌於 HTML,那透過 JSON 格式,將資料產生出來給 JavaScript 用,哦耶!
CSV
讀取資料
diablo.csv
ID,CHARACTER,LV
1,Amazon,1
2,Necromancer,89
3,Barbarian,67
4,Sorceress,23
5,Paladin,45
main.php
fgetcsv() 在剖析雙位元組字串(如中文)時,會錯漏資料,例如 "1,王子麵,5" 剖析成 "1" 和 "王子麵,5" 兩筆資料,而不是 1、王子麵、5 三筆資料。解決辦法是在使用前呼叫 setlocale(LC_ALL, 'en_US.UTF-8') 或 setlocale(LC_ALL, 'zh_TW.BIG5'),端看你檔案的字元編碼而定。
修改和寫入還有更好的讀取方式
main.php
偽 HEX 檔案
其實還是純文字文件,只是文字被編碼了。
將數值寫入檔案
fwrite() 或 fputs() 會將數值轉為字串再寫入檔案,就算 fopen() 第二個參數下了 'b' 也一樣。解法是用 pack() 將數值轉為 binary string 後再寫入~
列出所有檔案和子目錄
做法一:使用 opendir()、readdir()、closedir()
列出能設定的 php.ini 項目
$value1)
foreach ($value1 as $key2=>$value2)
if ($key2 == 'access' && ($value2 == 1 || $value2 == 7))
echo $key1, PHP_EOL;