首頁 >後端開發 >php教程 >PHP主| 5啟發性(有用)PHP片段

PHP主| 5啟發性(有用)PHP片段

Joseph Gordon-Levitt
Joseph Gordon-Levitt原創
2025-02-26 08:41:09300瀏覽

PHP Master | 5 Inspiring (and Useful) PHP Snippets

網絡上充斥著各種“X個PHP代碼片段”類型的文章,為什麼還要再寫一篇呢?原因很簡單:大多數文章中的代碼片段都乏善可陳。生成隨機字符串或返回$_SERVER["REMOTE_ADDR"]獲取客戶端IP地址之類的片段實在缺乏趣味性和實用性。本文將分享五個實用且有趣的PHP代碼片段,並介紹它們背後的靈感來源。希望這些富有創意的代碼片段能啟發您在日常編程中編寫更出色、更具創意的代碼。

關鍵要點

  • 本文介紹了五個實用的PHP代碼片段,包括使用內置fputcsv()函數生成CSV數據、使用PSR-0標準自動加載類、使用unpack()函數解析定長數據、使用一個簡單的PHP類進行HTML模板化以及使用file_get_contents作為cURL的替代方案來發出HTTP GET和POST請求。
  • 作者強調了使用PHP內置函數和創建自定義解決方案來執行常見任務(例如生成CSV數據或自動加載類)的重要性,這可以提高編碼效率和創造力。
  • 作者還討論了使用PHP代碼片段的益處和潛在風險,建議雖然它們可以極大地提高生產力並提高代碼可讀性,但應謹慎使用,在安全的環境中進行測試,並從可信的來源獲取,以避免潛在的問題或安全風險。

1. 生成CSV

我們經常看到這樣的代碼,試圖將多維數組數據轉換為CSV:

<code class="language-php"><?php
$csv = "";
foreach ($data as $row) {
    $csv .= join(",", $row) . "\n";
}
echo $csv;
?></code>

問題在於各個元素沒有正確轉義,單個值中包含引號或逗號都可能導致後續解析CSV數據時出錯。最好使用內置的fputcsv()函數;它的實現是用C代碼編寫的,因此執行速度更快,並且會為您處理必要的引用/轉義。以下代碼封裝了從數據數組構造CSV輸出的邏輯。它包含可選參數,允許使用標題列,以及是否將CSV直接刷新到瀏覽器或將輸出作為字符串返回。其巧妙之處在於將流與fputcsv()一起使用,因為該函數需要打開的文件句柄才能操作。

<code class="language-php"><?php
function toCSV(array $data, array $colHeaders = array(), $asString = false) {
    $stream = ($asString)
        ? fopen("php://temp/maxmemory", "w+")
        : fopen("php://output", "w");

    if (!empty($colHeaders)) {
        fputcsv($stream, $colHeaders);
    }

    foreach ($data as $record) {
        fputcsv($stream, $record);
    }

    if ($asString) {
        rewind($stream);
        $returnVal = stream_get_contents($stream);
        fclose($stream);
        return $returnVal;
    } else {
        fclose($stream);
    }
}
?></code>

有了toCSV()函數,生成CSV變得簡單且可靠。

2. 自動加載類

自動加載類文件很常見,但您可能不喜歡各種PHP框架提供的那些臃腫、重量級的自動加載器,或者您可能只是喜歡自己編寫解決方案。幸運的是,您可以編寫自己的最小加載器,並且仍然符合PHP標準工作組採用的PSR-0標準,我曾在自己的博客上首次演示了這一點。該標準並未描述PSR-0兼容的自動加載器必須提供的支持功能(註冊方法、配置選項等)。如果它能夠自動在<vendor name>(<namespace>)</namespace></vendor>模式中找到類定義,那麼它就是PSR-0兼容的。此外,它沒有指定<vendor name></vendor>的父目錄。大多數自動加載器實現的額外“填充”如果您需要通過代碼指定位置則很方便,但如果您只是使用PHP的include路徑中已有的目錄,則沒有必要。

<code class="language-php"><?php
$csv = "";
foreach ($data as $row) {
    $csv .= join(",", $row) . "\n";
}
echo $csv;
?></code>

這裡的巧妙之處在於正則表達式,它將傳入的名稱拆分為其組成部分;類名始終位於$match[2]中,$match[1]是命名空間名稱,它可能是空字符串。必須識別這些部分,因為下劃線在命名空間部分中沒有任何特殊含義,因此對下劃線和反斜杠進行盲目替換是不正確的。

3. 使用unpack()解析定長數據

在當今充斥著XML和JSON的現代世界中,您可能會認為定長格式已經滅絕……但您錯了。仍然存在大量的定長數據,例如某些日誌條目、MARC 21(書目信息)、NACHA(財務信息)等。老實說,我對定長數據仍然情有獨鍾。

在C等語言中,定長數據相對容易處理,因為數據一旦加載到內存中,就會與訪問數據結構完美對齊。但是對於某些人來說,在PHP等動態語言中處理定長數據可能是一場鬥爭;該語言的鬆散類型使得這種內存訪問變得不可能。因此,我們經常看到這樣的代碼:

<code class="language-php"><?php
function toCSV(array $data, array $colHeaders = array(), $asString = false) {
    $stream = ($asString)
        ? fopen("php://temp/maxmemory", "w+")
        : fopen("php://output", "w");

    if (!empty($colHeaders)) {
        fputcsv($stream, $colHeaders);
    }

    foreach ($data as $record) {
        fputcsv($stream, $record);
    }

    if ($asString) {
        rewind($stream);
        $returnVal = stream_get_contents($stream);
        fclose($stream);
        return $returnVal;
    } else {
        fclose($stream);
    }
}
?></code>

您可能感到不適。沒關係,我也不想在我的應用程序中使用這樣的代碼!它冗長且索引容易出錯。幸運的是,有一個更好的替代方案:unpack()

PHP手冊中unpack()的文檔指出:“根據給定的格式將二進製字符串解包到數組中”,並顯示了使用二進制數據轉義的用法示例。可能並非立即顯而易見的是,由於格式說明符“A”表示字符(畢竟,字符串不只是一系列位和字節嗎?),因此該函數可用於解析定長字符串。

使用unpack(),上述示例可以更優雅地改寫如下:

<code class="language-php"><?php
spl_autoload_register(function ($classname) {
    $classname = ltrim($classname, "\");
    preg_match('/^(.+)?([^\]+)$/U', $classname, $match);
    $classname = str_replace("\", "/", $match[1])
        . str_replace(["\", "_"], "/", $match[2])
        . ".php";
    include_once $classname;
});
?></code>

在這種情況下,格式字符串只是一系列A,指定字符數據、特定字段的字符數以及檢索到的數據將在最終數組中分配的鍵名,用斜杠分隔。例如,A6date會解析出6個字符,並將其作為$header["date"]提供。

4. HTML模板化

在PHP社區中,關於模板化一直沒有達成太多共識。我們都同意將HTML和PHP分開是可取的,但在使用Smarty或Twig等模板庫的適用性上存在衝突。一些人指出PHP本身就是一個模板引擎,並反對庫的速度、語法等。其他人聲稱從使用模板系統提供的DSL中獲益匪淺。一種折衷方案是使用用PHP編寫的非常小的類來模板化您的HTML以保持代碼簡潔。

<code class="language-php"><?php
$csv = "";
foreach ($data as $row) {
    $csv .= join(",", $row) . "\n";
}
echo $csv;
?></code>

它不是一個成熟的模板引擎;而是一個簡潔的輔助類,充當“存儲桶”,收集鍵/值數據對,您可以在指定為模板的包含文件中訪問這些數據對。首先,您在視圖中創建一個Template類的實例,可以選擇傳遞一個目錄名稱來查找後續的模板文件(允許您對相關文件進行分組)。然後,將應填充模板的值提供給set()方法或作為裸屬性。一旦指定所有值,您就可以調用out()方法來呈現模板。

<code class="language-php"><?php
function toCSV(array $data, array $colHeaders = array(), $asString = false) {
    $stream = ($asString)
        ? fopen("php://temp/maxmemory", "w+")
        : fopen("php://output", "w");

    if (!empty($colHeaders)) {
        fputcsv($stream, $colHeaders);
    }

    foreach ($data as $record) {
        fputcsv($stream, $record);
    }

    if ($asString) {
        rewind($stream);
        $returnVal = stream_get_contents($stream);
        fclose($stream);
        return $returnVal;
    } else {
        fclose($stream);
    }
}
?></code>

示例的mytemplate.php文件可能如下所示:

<code class="language-php"><?php
spl_autoload_register(function ($classname) {
    $classname = ltrim($classname, "\");
    preg_match('/^(.+)?([^\]+)$/U', $classname, $match);
    $classname = str_replace("\", "/", $match[1])
        . str_replace(["\", "_"], "/", $match[2])
        . ".php";
    include_once $classname;
});
?></code>

在模板文件中,您可以訪問PHP功能的全部範圍,以根據需要格式化值、過濾值等。

out()的第二個可選參數可以指定將模板內容作為字符串返回,而不是直接將其刷新到瀏覽器,您可以利用它來用先前填充的模板的結果替換一個模板中的佔位符。

5. 使用file_get_contents作為cURL的替代方案

cURL是一個用於通過各種協議進行通信的強大庫。它確實功能非常強大,有時沒有其他方法可以做到。如果您明確需要cURL公開的功能來完成您的任務,那麼請使用cURL!但是,PHP中日常cURL使用的大部分內容都圍繞發出HTTP GET和POST請求,這可以使用PHP內置函數輕鬆完成。

依賴cURL發出HTTP請求的問題有兩個:1)即使是最簡單的交易,也經常需要設置許多選項,以及2)它是一個擴展,根據您的託管和安裝情況,它可能可用也可能不可用;它是一個常見的擴展,但默認情況下未啟用。

file_get_contents()stream_context_create()是自4.3版本以來一直可用的兩個原生PHP函數。結合使用,它們可以執行許多與cURL通常執行的相同類型的請求。

對於基本的GET請求,可以使用file_get_contents()本身:

<code class="language-php"><?php
// 解析NACHA报头记录
$row = fread($fp, 94);
$header = array();
$header["type"] = substr($row, 0, 1);
$header["priority"] = substr($row, 1, 2);
$header["immDest"] = substr($row, 3, 10);
$header["immOrigin"] = substr($row, 13, 10);
$header["date"] = substr($row, 23, 6);
$header["time"] = substr($row, 29, 4);
$header["sequence"] = substr($row, 33, 1);
$header["size"] = substr($row, 34, 3);
$header["blockFactor"] = substr($row, 37, 2);
$header["format"] = substr($row, 39, 1);
$header["destName"] = substr($row, 40, 23);
$header["originName"] = substr($row, 63, 23);
$header["reference"] = substr($row, 86, 8);
print_r($header);
?></code>

對於需要指定HTTP標頭的請求(無論是GET還是其他任何HTTP方法),您可以通過將一個特殊鍵控數組傳遞給stream_context_create()來創建一個上下文,然後將上下文傳遞給file_get_contents()

<code class="language-php"><?php
// 解析NACHA报头记录
$row = fread($fp, 94);
$header = unpack("A1type/A2priority/A10immDest/A10immOrigin/"
    . "A6date/A4time/A1sequence/A3size/A2blockFactor/A1format/"
    . "A23destName/A23originName/A8reference", $row);
print_r($header);
?></code>

上面的示例顯示了通過POST上傳文件,上下文數組使用鍵“method”、“header”和“content”指定事務所需的信

息。

當將file_get_contents()用於復雜的請求(例如文件上傳)時,首先創建一個模擬Web表單並通過啟用了firebug的Firefox或類似工具運行它,然後檢查請求中包含的內容可能會有所幫助。從那裡您可以推斷出要包含的重要標頭元素。

總結

希望您覺得本文中介紹的代碼片段很有趣。它們展示了創造性的問題解決方法以及將PHP的內置功能用於新的效果。我希望您發現它們有用且鼓舞人心。如果您有自己鼓舞人心的代碼片段,請隨時在下面的評論中分享。

(圖片來自Fotolia)

(關於PHP代碼片段的常見問題)

(此處省略了FAQ部分,因為原文FAQ部分內容與代碼片段本身關係不大,屬於補充說明,可以根據實際需求自行添加或修改。)

以上是PHP主| 5啟發性(有用)PHP片段的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn