PHP最佳實踐指南:第一部分(中英對照)

靜好先生發表於2019-03-26

原文連結

A short, practical guide for common and confusing PHP tasks

一個簡短的實用指南,用於常見的和令人困惑的PHP任務

Last revised & maintainers 最後修改和維護人員

This document was last reviewed on January 25, 2019. It was last changed on February 20, 2019. It’s maintained by me, Alex Cabal. I’ve been writing PHP for a long time now, and currently I run Scribophile, an online writing group for serious writers, Writerfolio, an easy online writing portfolio for freelancers, and Standard Ebooks, an open source project that produces liberated ebooks for the true book lover. Drop me a line if you think I can help you with something, or with suggestions or corrections to this document.

這份檔案最後一次審查是在2019年1月25日。最後一次更改是在2019年2月20日。 它是由我Alex Cabal維護的。我已經編寫PHP很長時間了,目前我執行於Scribophile,這是一個面向嚴肅作家的線上寫作小組,Writerfolio,這是一個面向自由作家的簡單的線上寫作組合,還有Standard Ebooks,這是一個開源專案,為真正的圖書愛好者提供免費的電子書。 如果你認為我能幫你做些什麼,或者對這份檔案有什麼建議或修改,請給我寫信。

Introduction

PHP is a complex language that has suffered years of twists, bends, stretches, and hacks. It’s highly inconsistent and sometimes buggy. Each version has its own unique features, warts, and quirks, and it’s hard to keep track of what version has what problems. It’s easy to see why it gets as much hate as it does sometimes.

PHP是一種複雜的語言,經歷了多年的歪曲、誇大和詆譭。這是高度不合邏輯和反常的。每個版本都有自己獨特的特性、缺點和怪癖,很難跟蹤哪個版本有哪些問題。很容易理解為什麼有時候會有那麼多的仇恨。

Despite that, it’s the most popular language on the web today. Because of its long history, you’ll find lots of tutorials on how to do basic things like password hashing and database access. The problem is that out of five tutorials, you have a good chance of finding five totally different ways of doing something. Which way is the “right” way? Do any of the other ways have subtle bugs or gotchas? It’s really hard to find out, and you’ll be bouncing around the internet trying to pin down the right answer.

儘管如此,它仍然是當今網路上最流行的語言。由於其悠久的歷史,您將發現許多教程,如何做基本的事情,如密碼雜湊和資料庫訪問。問題是,在五篇教程中,您很有可能找到五種完全不同的方法。哪條路是“正確”的?其他方法是否有細微的bug或陷阱?這真的很難找到,你會在網際網路上跳來跳去試圖找到正確的答案。

That’s also one of the reasons why new PHP programmers are so frequently blamed for ugly, outdated, or insecure code. They can’t help it if the first Google result was a four-year-old article teaching a five-year-old method!

這也是為什麼新的PHP程式設計師經常因為醜陋、過時或不安全的程式碼而受到指責的原因之一。如果谷歌的第一個結果是四年前的一篇文章教的是五年前的方法,那他們就沒辦法了!

This document tries to address that. It’s an attempt to compile a set of basic instructions for what can be considered best practices for common and confusing issues and tasks in PHP. If a low-level task has multiple and confusing approaches in PHP, it belongs here.

本文件試圖解決這個問題。它試圖編譯一組基本指令,用於PHP中常見和令人困惑的問題和任務的最佳實踐。如果一個低階任務在PHP中有多種令人困惑的方法,那麼它就屬於這裡。

What this is 這是什麼

It’s a guide suggesting the best direction to take when facing one of the common low-level tasks a PHP programmer might encounter that are unclear because of the many options PHP might offer. For example: connecting to a database is a common task with a large amount of possible solutions in PHP, not all of them good ones—thus, it’s included in this document.

這是一份指南,建議在面對PHP程式設計師可能遇到的常見低階任務時採取的最佳方向。由於PHP可能提供許多選項,這些任務並不清楚。例如:連線到資料庫是一項常見的任務,在PHP中有大量可能的解決方案,但並不是所有的都是好的解決方案——因此,本文包含了這些解決方案。

It’s a series of short, introductory solutions. Examples should get you up and running in a basic setting, and you should do your own research to flesh them out into something useful to you.

它是一系列簡短的介紹性解決方案。示例應該讓您在基本設定中啟動和執行,並且您應該自己進行研究,將它們充實成對您有用的內容。

It points to what we consider the state-of-the-art of PHP. However, this means that if you’re using an older version of PHP, some of the features required to pull off these solutions might not be available to you. This is a living document that I’ll do my best to keep updated as PHP continues to evolve.

它指出了我們認為最先進的PHP。然而,這意味著如果您使用的是較老版本的PHP,那麼實現這些解決方案所需的一些特性可能對您來說是不可用的。 這是一個動態的文件,隨著PHP的不斷髮展,我將盡力保持更新。

What this isn’t 這不是什麼

This document is not a PHP tutorial. You should learn the basics and syntax of the language elsewhere.

本文件不是PHP教程。您應該在其他地方學習該語言的基礎知識和語法。

It’s not a guide to common web application problems like cookie storage, caching, coding style, documentation, and so on.

它不是關於常見web應用程式問題(如cookie儲存、快取、編碼風格、文件等)的指南。

It’s not a security guide. While it touches upon some security-related issues, you’re expected to do your own research when it comes to securing your PHP apps. In particular, you should carefully review any solution proposed here before implementing it. Your code, and your copy and paste, is your own fault.

它不是安全指南。雖然它涉及到一些與安全相關的問題,但是當涉及到保護PHP應用程式時,您需要自己進行研究。特別是,在實現它之前,您應該仔細檢查這裡提出的任何解決方案。您的程式碼,以及您的複製和貼上,都是您自己的錯誤。

It’s not an advocate of a certain coding style, pattern, or framework.

它並不提倡某種編碼風格、模式或框架

It’s not an advocate for a certain way of doing high-level tasks like user registration, login systems, etc. This document is strictly for low-level tasks that, because of PHP’s long history, might be confusing or unclear.

它並不提倡用某種方式來完成高階任務,比如使用者註冊、登入系統等等。本文件嚴格適用於低層任務,由於PHP的歷史很長,這些任務可能令人困惑或不清楚。

It’s not a be-all and end-all solution, nor is it the only solution. Some of the methods described below might not be what’s best for your particular situation, and there are lots of different ways of achieving the same ends. In particular, high-load web apps might benefit from more esoteric solutions to some of these problems.

它不是萬能的解決方案,也不是唯一的解決方案。下面描述的一些方法可能並不適合您的特定情況,並且有許多不同的方法可以達到相同的目的。特別是,高負載web應用程式可能會受益於這些問題的一些更深奧的解決方案

What PHP version are we using? 我們使用的是什麼PHP版本?

PHP 7.2.10-0ubuntu0.18.04.1, installed on Ubuntu 18.04 LTS.

PHP is the 100-year-old tortoise of the web world. Its shell is inscribed with a rich, convoluted, and gnarled history. In a shared-hosting environment, its configuration might restrict what you can do.

PHP是web世界的百年老古董。它的外殼上鐫刻著豐富、曲折、多節的歷史。在共享宿主環境中,其配置可能會限制您的操作

In order to retain a scrap of sanity, we’re going to focus on just one version of PHP: PHP 7.2.10-0ubuntu0.18.04.1. This is the version of PHP you’ll get if you install it using apt-get on an Ubuntu 18.04 LTS server. In other words, it’s the sane default used by many.

為了保持一點理智,我們只關注PHP的一個版本:PHP 7.2.10-0ubuntu0.18.04.1。如果您在Ubuntu 18.04 LTS伺服器上使用apt-get安裝PHP,就會得到這個版本。換句話說,這是許多人使用的正常預設值。

You might find that some of these solutions work on different or older versions of PHP. If that’s the case, it’s up to you to research the implications of subtle bugs or security issues in these older versions.

您可能會發現,其中一些解決方案適用於不同或較老版本的PHP。如果是這樣的話,就由您來研究這些舊版本中細微的bug或安全問題的含義。

Storing passwords

Use the built-in password hashing functions to hash and compare passwords.

使用內建的密碼雜湊函式雜湊和比較密碼。

Hashing is the standard way of protecting a user’s password before it’s stored in a database. Many common hashing algorithms like md5 and even sha1 are unsafe for storing passwords, because hackers can easily crack passwords hashed using those algorithms.

雜湊是在使用者密碼儲存到資料庫之前保護其密碼的標準方法。許多常見的雜湊演算法,如md5甚至sha1,對於儲存密碼都是不安全的,因為黑客可以很容易地破解使用這些演算法雜湊的密碼。

Example

<?php
// Hash the password.  $hashedPassword will be a 60-character string.
$hashedPassword = password_hash('my super cool password', PASSWORD_DEFAULT);
 
// You can now safely store the contents of $hashedPassword in your database!
 
// Check if a user has provided the correct password by comparing what they typed with our hash
password_verify('the wrong password', $hashedPassword); // false
 
password_verify('my super cool password', $hashedPassword); // true
?>
複製程式碼

Gotchas 陷阱

  • Many sources will recommend that you also “salt” your password before hashing it. That’s a great idea, and password_hash() already salts your password for you. That means that you don’t have to salt it yourself.

    許多資料來源會建議您在雜湊密碼之前也要“加鹽”。這是個好主意,但是password_hash()已經為您做了“加鹽”。這意味著你不需要自己再加鹽。

Further reading 延伸閱讀

Connecting to and querying a MySQL database 連線並查詢MySQL資料庫

Use PDO and its prepared statement functionality.

使用PDO及其準備好的語句功能。

There are many ways to connect to a MySQL database in PHP. PDO (PHP Data Objects) is the newest and most robust of them. PDO has a consistent interface across many different types of database, uses an object-oriented approach, and supports more features offered by newer databases.

在PHP中,有許多方法可以連線到MySQL資料庫。PDO (PHP資料物件)是其中最新的、最健壯的。PDO具有跨許多不同型別資料庫的一致介面,使用物件導向的方法,並支援更新資料庫提供的更多特性。

You should use PDO’s prepared statement functions to help prevent SQL injection attacks. Using the bindValue() function ensures that your SQL is safe from first-order SQL injection attacks. (This isn’t 100% foolproof though, see Further Reading for more details.) In the past, this had to be achieved with some arcane combination of “magic quote” functions. PDO makes all that gunk unnecessary.

您應該使用PDO的預處理語句函式來幫助防止SQL隱碼攻擊。使用bindValue()函式可以確保SQL不會受到一階SQL隱碼攻擊。(不過,這並不是100%萬無一失的,更多細節請參閱後續閱讀。)在過去,這必須通過一些神祕的“magic quote”函式組合來實現。PDO讓所有的奇技淫巧都沒有必要了。

Example

<?php
// Create a new connection.
// You'll probably want to replace hostname with localhost in the first parameter.
// Note how we declare the charset to be utf8mb4.  This alerts the connection that we'll be passing UTF-8 data.  This may not be required depending on your configuration, but it'll save you headaches down the road if you're trying to store Unicode strings in your database.  See "Gotchas".
// The PDO options we pass do the following:
// PDO::ATTR_ERRMODE enables exceptions for errors.  This is optional but can be handy.
// PDO::ATTR_PERSISTENT disables persistent connections, which can cause concurrency issues in certain cases.  See "Gotchas".
$link = new PDO(    'mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',
                    'your-username',
                    'your-password',
                    array(
                        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                        PDO::ATTR_PERSISTENT => false
                    )
                );
 
$handle = $link->prepare('select Username from Users where UserId = ? or Username = ? limit ?');
 
$handle->bindValue(1, 100);
$handle->bindValue(2, 'Bilbo Baggins');
$handle->bindValue(3, 5);
 
$handle->execute();
 
// Using the fetchAll() method might be too resource-heavy if you're selecting a truly massive amount of rows.
// If that's the case, you can use the fetch() method and loop through each result row one by one.
// You can also return arrays and other things instead of objects.  See the PDO documentation for details.
$result = $handle->fetchAll(PDO::FETCH_OBJ);
 
foreach($result as $row){
    print($row->Username);
}
?>
複製程式碼

Gotchas 陷阱

  • Not having set the character set to utf8mb4 in the connection string might cause Unicode data to be stored incorrectly in your database, depending on your configuration.

    在連線字串中沒有將字符集設定為utf8mb4可能會導致Unicode資料在資料庫中儲存不正確,這取決於您的配置。

  • Even if you declare your character set to be utf8mb4, make sure that your actual database tables are in the utf8mb4 character set. For why we use utf8mb4 instead of just utf8, check the PHP and UTF-8 section.

    即使將字符集宣告為utf8mb4,也要確保實際的資料庫表是utf8mb4字符集。 要了解為什麼我們使用utf8mb4而不是utf8,請檢查PHP和UTF-8部分。

  • Enabling persistent connections can possibly lead to weird concurrency-related issues. This isn’t a PHP problem, it’s an app-level problem. Persistent connections are safe to use as long as you consider the consequences. See this Stack Overflow question.

    啟用持久連線可能會導致奇怪的併發相關問題。這不是PHP問題,而是應用程式級別的問題。只要考慮到後果,使用持久連線是安全的。參見這個堆疊溢位問題

Further reading 延伸閱讀

PHP tags PHP標籤

Use <?php ?>.

There are a few different ways to delimit blocks of PHP: <?php ?>, <?= ?>, <? ?>, and <% %>. While the shorter ones might be more convenient to type, they’re disabled by default and must be enabled by configuring the PHP server with the short_open_tag option. Therefore the only method that’s guaranteed to work on all PHP servers is <?php ?>. If you ever plan on deploying your PHP to a server whose configuration you can’t control, then you should always use <?php ?>.

有幾種不同的方法來分隔PHP塊:<?php ?>, <?= ?>, <? ?>, 和 <% %>。雖然較短的選項可能更便於輸入,但它們在預設情況下是禁用的,必須使用short_open_tag選項配置PHP伺服器來啟用它們。因此,保證在所有PHP伺服器上工作的唯一方法是<?php ? >。如果您計劃將PHP部署到無法控制其配置的伺服器,那麼應該始終使用<?php ? >。

Fortunately <?= is available regardless of whether or not short tags are enabled, so it’s always safe to use that shorthand instead of <? php print() ?>.

幸運的是<?= 是可用的,不管是否啟用了短標記,所以使用這種簡寫代替<?php print () ? >也是安全的。

If you’re only coding for yourself and have control over the PHP configuration you’ll be using, you might find the shorter tags to be more convenient. But remember that <? ?>; might conflict with XML declarations and <% %> is actually ASP style. Whatever you choose, make sure you stay consistent!

如果您只是為自己編寫程式碼,並且能夠控制將要使用的PHP配置,那麼您可能會發現更短的標記更方便。但是記得<? ?>可能與XML宣告衝突,<% %>實際上是ASP風格。無論你選擇什麼,一定要保持一致!

Gotchas 陷阱

  • When including a closing ?> tag in a pure PHP file (for example, in a file that only contains a class definition), make sure not to leave any trailing newlines after it. While the PHP parser safely “eats” a single newline character after the closing tag, any other newlines might be outputted to the browser and possibly confuse things if you’re outputting any HTTP headers later.

    當在純PHP檔案中包含一個關閉 ?>標記時(例如,在一個只包含類定義的檔案中),請確保不要在它後面留下任何尾隨的換行符。雖然PHP解析器在結束標記之後安全地“吃掉”了一個換行符,但是任何其他換行符都可能輸出到瀏覽器中,如果稍後輸出任何HTTP頭資訊,可能會造成混淆。

  • When writing a web app targeting older versions of IE, make sure not to leave a newline between any closing ?>; tag and the html <!doctype> tag. Old versions of IE will enter quirks mode if they encounter any white space, including newlines, before the doctype declaration. This isn’t an issue for newer versions of IE and other, more advanced browsers. (Read: every other browser besides IE.)

    當編寫一個針對較老版本IE的web應用程式時,請確保在任何結束符?>標籤和html <!doctype之間不要留下新的換行。因為舊版本的IE在doctype宣告之前遇到任何空白(包括換行),就會進入quirks模式。對於更新版本的IE和其他更高階的瀏覽器來說,這不是問題。(閱讀:除IE之外的所有其他瀏覽器。)

Further reading 擴充套件閱讀

Auto-loading classes 自動載入類

Use spl_autoload_register() to register your auto-load function.

使用spl_autoload_register()來註冊您的自動載入函式

PHP provides several ways to auto-load files containing classes that haven’t yet been loaded. The older way is to use a magic global function called __autoload(). However you can only have one __autoload() function defined at once, so if you’re including a library that also uses the __autoload() function, then you’ll have a conflict.

PHP提供了幾種方法來自動載入包含尚未載入的類的檔案。較老的方法是使用一個名為__autoload()的全域性魔術函式。但是,您一次只能定義一個__autoload()函式,所以如果您包含一個也使用了__autoload()函式的庫,那麼您將會遇到衝突。

The correct way to handle this is to name your autoload function something unique, then register it with the spl_autoload_register() function. This function allows more than one __autoload() function to be defined, so you won’t step on any other code’s own __autoload() function.

處理此問題的正確方法是將autoload函式命名為惟一的,然後使用spl_autoload_register()函式註冊它。這個函式允許定義多個_autoload()函式,因此您不會踩到任何其他程式碼自己的_autoload()函式。

Example

<?php
// First, define your auto-load function.
function MyAutoload($className){
    include_once($className . '.php');
}
 
// Next, register it with PHP.
spl_autoload_register('MyAutoload');
 
// Try it out!
// Since we haven't included a file defining the MyClass object, our auto-loader will kick in and include MyClass.php.
// For this example, assume the MyClass class is defined in the MyClass.php file.
$var = new MyClass();
?>
複製程式碼

Further reading 擴充套件閱讀

Single vs. double quotes from a performance perspective 從效能的角度來看,單引號和雙引號

It doesn’t really matter. 這並不重要。

A lot of ink has been spilled about whether to define strings with single quotes (‘) or double quotes (“). Single-quoted strings aren’t parsed, so whatever you’ve put in the string, that’s what will show up. Double-quoted strings are parsed and any PHP variables in the string are evaluated. Additionally, escaped characters like \n for newline and \t for tab are not evaluated in single-quoted strings, but are evaluated in double-quoted strings.

關於是使用單引號(')定義字串還是使用雙引號(")定義字串,已經花費了大量的筆墨。單引號字串不會被解析,所以無論你在字串中放入了什麼,都會顯示出來。雙引號字串解析並計算字串中的任何PHP變數。此外,換行的\n和製表符的\t等轉義字元不在單引號字串中求值,而是在雙引號字串中求值。

Because double-quoted strings are evaluated at run time, the theory is that using single-quoted strings will improve performance because PHP won’t have to evaluate every single string. While this might be true on a certain scale, for the average real-life application the difference is so small that it doesn’t really matter. So for an average app, it doesn’t matter what you choose. For extremely high-load apps, it might matter a little. Make a choice depending on what your app needs, but whatever you choose, be consistent.

因為雙引號字串是在執行時計算的,所以理論上使用單引號字串將提高效能,因為PHP不必計算每個字串。雖然這在一定程度上可能是正確的,但是對於實際的應用程式來說,這種差異非常小,所以實際上並不重要。所以對於一個普通的應用,你選擇什麼並不重要。對於非常高負載的應用程式,這可能有點關係。根據您的應用程式的需要做出選擇,但是無論您選擇什麼,都要保持一致。

Further reading

PHP and Memcached

If you need a distributed cache, use the Memcached client library. Otherwise, use APCu.

如果需要分散式快取,請使用Memcached客戶機庫。否則,使用APCu。

A caching system can often improve your app’s performance. Memcached is a popular choice and it works with many languages, including PHP.

快取系統通常可以提高應用程式的效能。Memcached是一個流行的選擇,它可以與許多語言相容,包括PHP。

However, when it comes to accessing a Memcached server from a PHP script, you have two different and very stupidly named choices of client library: Memcache and Memcached. They’re different libraries with almost the same name, and both are used to access a Memcached instance.

然而,當涉及到從PHP指令碼訪問Memcached伺服器時,您有兩個不同的客戶端擴充套件庫選擇,它們的名稱都非常愚蠢:Memcache和Memcached。它們是名稱幾乎相同的不同庫,都用於訪問Memcached例項。

It turns out that the Memcached library is the one that best implements the Memcached protocol. It includes a few useful features that the Memcache library doesn’t, and seems to be the one most actively developed.

事實證明,Memcached庫是最好地實現Memcached協議的庫。它包含一些Memcache庫沒有的有用特性,而且似乎是發展最活躍的。

However if you don’t need to access a Memcached instance from a series of distributed servers, then use APCu instead. APCu is supported by the PHP project and has much of the same functionality as Memcached.

但是,如果不需要從一系列分散式伺服器訪問Memcached例項,則使用APCu。APCu由PHP專案支援,並且具有與Memcached相同的功能。

Installing the Memached client library After you install the Memcached server, you need to install the Memcached client library. Without the library, your PHP scripts won’t be able to communicate with the Memcached server.

安裝Memached客戶端擴充套件庫 安裝Memcached伺服器之後,需要安裝Memcached客戶機庫。如果沒有這個庫,您的PHP指令碼將無法與Memcached伺服器通訊。

You can install the Memcached client library on Ubuntu 16.04 by running this command in your terminal:

你可以在你的終端上執行這個命令在Ubuntu 16.04上安裝Memcached客戶端庫:

user@localhost: sudo apt-get install php-memcached
複製程式碼

Using APCu instead

Before Ubuntu 14.04, the APC project was both an opcode cache and a Memcached-like key-value store. Since the version of PHP that ships since Ubuntu 14.04 now includes a built-in opcode cache, APC was split into the APCu project, which is essentially APC’s key-value storage functionality—AKA the “user cache”, or the “u” in APCu—without the opcode-cache parts.

在Ubuntu 14.04之前,APC專案既是一個操作碼快取,也是一個類似memcache的鍵值儲存。由於Ubuntu 14.04之後釋出的PHP版本現在包含了一個內建的操作碼快取,APC被分割成APCu專案,APCu專案本質上是APC的key-value儲存功能——也就是APCu中的“user cache”或“u”——沒有操作碼快取部分。

Installing APCu

You can install APCu on Ubuntu 16.04 by running this command in your terminal:

你可以通過在你的終端執行這個命令在Ubuntu 16.04上安裝APCu:

sudo apt-get install php-apcu
複製程式碼

Example

<?php
// Store some values in the APCu cache.  We can optionally pass a time-to-live, but in this example the values will live forever until they're garbage-collected by APCu.
apcu_store('username-1532', 'Frodo Baggins');
apcu_store('username-958', 'Aragorn');
apcu_store('username-6389', 'Gandalf');
 
// You can store arrays and objects too.
apcu_store('creatures', array('ent', 'dwarf', 'elf'));
apcu_store('saruman', new Wizard());
 
// After storing these values, any PHP script can access them, no matter when it's run!
$value = apcu_fetch('username-958', $success);
if($success === true){
    print($value); // Aragorn
}
 
$value = apcu_fetch('creatures', $success);
if($success === true){
    print_r($value);
}
 
$value = apcu_fetch('username-1', $success); // $success will be set to boolean false, because this key doesn't exist.
if($success !== true){ // Note the !==, this checks for true boolean false, not "falsey" values like 0 or empty string.
    print('Key not found');
}
 
apcu_delete('username-958'); // This key will no longer be available.
?>
複製程式碼

Gotchas 陷阱

  • If you’re migrating APCu code from a version of APUc before 16.04, note that the function names have changed from apc_* to apcu_*. For example, apc_store() became apcu_store().

    如果您正在從16.04之前的APUc版本遷移APCu程式碼,請注意函式名已經從apc_更改為apcu_。例如,apc_store()變成了apcu_store()。

Further reading 擴充套件閱讀

define() vs. const

Use define() unless readability, class constants, or micro-optimization are concerns.

除非關注可讀性、類常量或微優化,否則請使用define()。

Traditionally in PHP you would define constants using the define() function. But at some point PHP gained the ability to also declare constants with the const keyword. Which one should you use when defining your constants?

在PHP中,通常使用define()函式定義常量。但在某個時候,PHP也獲得了使用const關鍵字宣告常量的能力。定義常量時應該使用哪一個?

The answer lies in the little differences between the two methods.

答案在於這兩種方法之間的細微差別。

  1. define() defines constants at run time, while const defines constants at compile time. This gives const a very slight speed edge, but not one worth worrying about unless you’re building large-scale software.

    define()在執行時定義常量,而const在編譯時定義常量。這給了const一個非常小的速度優勢,但是不值得擔心,除非您正在構建大型軟體。

  2. define() puts constants in the global scope, although you can include namespaces in your constant name. That means you can’t use define() to define class constants.

    define()將常量放在全域性範圍內,不過可以在常量名稱中包含名稱空間。這意味著您不能使用define()來定義類常量。

  3. define() lets you use expressions both in the constant name and in the constant value, unlike const which allows neither. This makes define() much more flexible.

    define()允許您在常量名稱和常量值中同時使用表示式,而const不允許這兩者。這使得define()更加靈活。

  4. define() can be called within an if() block, while const cannot.

    define()可以在if()塊中呼叫,而const不能。

Example

<?php
// Let's see how the two methods treat namespaces
namespace MiddleEarthCreatures\Dwarves;
const GIMLI_ID = 1;
define('MiddleEarth\Creatures\Elves\LEGOLAS_ID', 2);
 
print(\MiddleEarth\Creatures\Dwarves\GIMLI_ID); // 1
print(\MiddleEarth\Creatures\Elves\LEGOLAS_ID); // 2; note that we used define(), but the namespace is still recognized
 
// Now let's declare some bit-shifted constants representing ways to enter Mordor.
define('TRANSPORT_METHOD_SNEAKING', 1 << 0); // OK!
const TRANSPORT_METHOD_WALKING = 1 << 1; // Compile error! const can't use expressions as values
 
// Next, conditional constants.
define('HOBBITS_FRODO_ID', 1);
 
if($isGoingToMordor){
    define('TRANSPORT_METHOD', TRANSPORT_METHOD_SNEAKING); // OK!
    const PARTY_LEADER_ID = HOBBITS_FRODO_ID // Compile error: const can't be used in an if block
}
 
// Finally, class constants
class OneRing{
    const MELTING_POINT_CELSIUS = 1000000; // OK!
    define('MELTING_POINT_ELVISH_DEGREES', 200); // Compile error: can't use define() within a class
}
?>
複製程式碼

Because define() is ultimately more flexible, it’s the one you should use to avoid headaches unless you specifically require class constants. Using const generally results in more readable code, but at the expense of flexibility. Whichever one you use, be consistent!

因為define()最終更加靈活,所以應該使用它來避免麻煩,除非特別需要類常量。使用const通常會產生更易於閱讀的程式碼,但這是以靈活性為代價的。 無論使用哪一個,都要保持一致!

Further reading

Caching PHP opcode PHP操作碼快取

Lucky you: PHP has a built-in opcode cache!

幸運的是:PHP有一個內建的操作碼快取!

In older versions of PHP, every time a script was executed it would have to be compiled from scratch, even if it had been compiled before. Opcode caches were additional software that saved previously compiled versions of PHP, speeding things up a bit. There were various flavors of caches you could choose from.

在較老版本的PHP中,每次執行指令碼時都必須從頭編譯,即使之前已經編譯過了。操作碼快取是另外一種軟體,它可以儲存以前編譯過的PHP版本,從而稍微加快速度。有各種各樣的快取可供選擇。

Lucky for us, the version of PHP that ships with Ubuntu 18.04 includes a built-in opcode cache that’s turned on by default. So there’s nothing for you to do!

幸運的是,附帶Ubuntu 18.04的PHP版本包含一個預設開啟的內建操作碼快取。所以你什麼不用做了!

Further reading 擴充套件閱讀

PHP and regex PHP和正規表示式

Use the PCRE (preg_*) family of functions.

使用PCRE (preg_*)函式家族。

Before PHP 7 came around, PHP had two different ways of using regular expressions: the PCRE (Perl-compatible, preg_) functions and the POSIX (POSIX extended, ereg_) functions.

在PHP 7出現之前,PHP有兩種使用正規表示式的方法:PCRE (perl相容的preg_)函式和POSIX (POSIX extended, ereg_)函式。

Each family of functions used a slightly different flavor of regular expression. Luckily for us, the ereg_* functions have been removed in PHP 7, so this source of confusion is past us.

每個函式家族使用的正規表示式略有不同。幸運的是,在PHP 7中已經刪除了ereg_*函式,所以這個困惑的根源已經過去了。

Gotchas 陷阱

  • Remember to use the /u flag when working with regexes, to ensure you’re working in Unicode mode.

    記住,在使用regexes時使用/u標誌,以確保在Unicode模式下工作。

Further Reading 擴充套件閱讀

相關文章