首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 程式設計師不可忽視的三大核心技能:變數/陣列進階、正則表達式實戰、模板引擎原理與實作

     編輯:PHP 綜合知識

PHP 繼承了 Perl 強大的正則、C 的指標語義、Shell 的字串處理,但許多開發者僅停留在 `echo`、`if`、`foreach` 表層。本文深入三大核心領域:**變數/陣列進階操作 (引用、可變變數、函數作為值)**、**PCRE 正則表達式實戰 (遞迴、前瞻、效能)**、**模板引擎原理與手寫實作 (詞法分析、編譯、快取)**,並給出進階練習題。

一、變數與陣列進階:PHP 獨特的動態特性

1. 可變變數與可變函數

<?php
$var = 'hello';
$varName = 'var';
echo $$varName; // hello

function greet(string $name): string { return "Hello $name"; }
$func = 'greet';
echo $func('World'); // Hello World

// 陣列作為呼叫式
$obj = new class { public function run() { return 'running'; } };
[$obj, 'run'](); // PHP 7.1+
?>

2. 引用傳遞與寫時複製 (Copy-on-Write)

<?php
function byRef(&$v) { $v++; }
function byVal($v) { $v++; }
$a = 1;
byRef($a); echo $a; // 2
byVal($a); echo $a; // 2 (注意:標量無 COW 行為)

$arr = [1,2,3];
$ref = &$arr; // 硬引用
$copy = $arr; // COW:實際未複製,修改時才分離
$copy[0] = 99;
echo $arr[0]; // 1 (已分離)
$ref[0] = 88;
echo $arr[0]; // 88 (同一記憶體)
?>

3. foreach 引用陷阱與解決

<?php
$arr = [1,2,3];
foreach ($arr as &$v) $v *= 2; // $v 為引用
unset($v); // **必須 unset**,否則 $v 仍指向最後一個元素
foreach ($arr as $v) { /* ... */ } // 此處 $v 為值複製,但若未 unset 會修改 $arr[2]
?>

4. 陣列進階函數:array_column、array_reduce、generator 迭代

<?php
$users = [
    ['id'=>1, 'name'=>'A', 'roles'=>['admin']],
    ['id'=>2, 'name'=>'B', 'roles'=>['user']],
];
$names = array_column($users, 'name'); // ['A','B']
$ids = array_column($users, 'id', 'name'); // ['A'=>1, 'B'=>2]

$sum = array_reduce($users, fn($carry, $u) => $carry + $u['id'], 0); // 3

// Generator 避免大陣列記憶體
function fetchUsers(PDO $pdo): Generator {
    $stmt = $pdo->query('SELECT * FROM users');
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) yield $row;
}
foreach (fetchUsers($pdo) as $user) { /* 處理單筆 */ }
?>

二、PCRE 正則表達式實戰:從入門到效能調優

1. 常用模式與修飾符

模式說明
`/pattern/iu`i=大小寫不敏感, u=UTF-8 模式 (必加)
`\p{L}`, `\p{N}`Unicode 字母/數字 (需 u 修飾符)
`(?...)`命名捕獲組, `$matches['name']` 存取
`(?:...)`非捕獲組, 分組不佔用編號
`(?=...)`, `(?!...)`正向/負向前瞻 (零寬斷言)
`(?>...)`原子組, 禁止回溯, 提升效能

2. 實戰範例:解析複雜字串

<?php
// 解析 CSS 色碼 #RGB, #RRGGBB, rgb(...), rgba(...)
$css = 'color: #f00; background: rgba(255,0,0,0.5); border: 1px solid #abcdef;';
preg_match_all('/
    \#(?:[0-9a-f]{3}|[0-9a-f]{6})\b
  | rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)
  | rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+?\s*\)
/ix', $css, $m);
print_r($m[0]);

// 郵件地址 (RFC 5322 簡化版)
$emailPattern = '/^(?[^@\s]+)@(?[^@\s]+\.[^@\s]+)$/';
preg_match($emailPattern, 'test@example.com', $m);
echo $m['local']; // test
?>

3. 效能殺手:災難性回溯與優化

<?php
// 惡意輸入導致指數級回溯
$evil = str_repeat('a', 10000) . '!';
$pattern = '/(a+)+b/'; // 災難性
// preg_match($pattern, $evil); // 會卡死

// 優化:使用原子組或佔有量詞
$pattern = '/(?>a+)b/'; // 或 /a++b/ (PHP 不支援 ++,用原子組)
$pattern = '/a+b/'; // 簡單情況無回溯問題
?>

原則:避免巢狀量詞 `(.*)*`、在固定前綴後使用 `.*?`、善用 `(*SKIP)(*FAIL)` 排除區塊。

三、模板引擎原理:從字串替換到編譯快取

1. 三代演進

  1. 字串替換:`str_replace(['{title}','{body}'], [$title,$body], $tpl)` — 簡單但無邏輯、無快取。
  2. 正則解析 + eval:`preg_replace_callback('/\{(\w+)\}/', fn($m) => $vars[$m[1]], $tpl)` — 支援變數,但 `eval` 不安全、難除錯。
  3. 編譯為 PHP 快取:將模板編譯為純 PHP 檔案,包含 ``,後續直接 `include` — 效能最佳、可除錯、支援繼承/區塊。

2. 手寫微型編譯器 (教學用)

<?php
class TinyTemplate {
    private string $cacheDir;
    public function __construct(string $cacheDir) { $this->cacheDir = $cacheDir; }
    
    public function render(string $tplName, array $vars = []): string {
        $cacheFile = $this->cacheDir . '/' . md5($tplName) . '.php';
        if (!is_file($cacheFile) || filemtime($cacheFile) < filemtime($tplName)) {
            $this->compile($tplName, $cacheFile);
        }
        extract($vars, EXTR_SKIP);
        ob_start();
        include $cacheFile;
        return ob_get_clean();
    }
    
    private function compile(string $tplFile, string $cacheFile): void {
        $tpl = file_get_contents($tplFile);
        // 簡單語法:{{ $var }} -> 
        $php = preg_replace_callback('/\{\{\s*(\$[\w->]+)\s*\}\}/', function($m) {
            return '';
        }, $tpl);
        // {% if $cond %}...{% endif %}
        $php = preg_replace('/\{\%\s*if\s+(\$[\w->]+)\s*\%\}(.*?)\{\%\s*endif\s*\%\}/s', 
            '$2', $php);
        file_put_contents($cacheFile, 'render(__DIR__.'/tpl/home.html', ['title' => '首頁', 'user' => ['name'=>'Admin']]);
?>

3. 生產級引擎選型

引擎特色適用
TwigSymfony 標準、沙箱、繼承、擴充性強、編譯快取大型專案、安全性要求高
BladeLaravel 內建、語法糖豐富、指令系統、零配置Laravel 專案
Plates原生 PHP、無編譯、輕量、易學中小專案、不想學新語法
LatteNette 核心、類型安全、自動逃逸、效能極佳追求型別安全、高效能
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved