Modern PHP讀書筆記一

來源:互聯網
上載者:User

關於PHP,大家的誤解比較多,但其實現代PHP是一門無論開發效率還是執行效率都相當高的程式設計語言。關於現代PHP的各方面特性,大家可以參考<Modern PHP>作者之前寫的 PHP the right way,中文翻譯:PHP之道。同時,作者也是比較流行的PHP架構 – Slim 的開發人員。所以這本書非常值得已讀,甚至你只需要懂一些OOP的概念即可,並不需要你懂PHP開發。

Part 1 Language Feature Features Namespaces Helpful Tips Code to an interface Trait Generators Closures Zend Opcache Built-in HTTP server Part 2 Good Pratices Standards PHP-FIG PSR PSR-1 Basic Coding standard PSR-2 Strict Code Style PSR-3 Logger Interface PSR-4 Autoloaders Components Components Composer Semantic Versioning Create PHP Components

Part 1. Language Feature Features Namespaces

PHP命名空間使用 “\” 字元來分割sumnamespaces。與作業系統的物理檔案系統不同,PHP命名空間是一個抽象概念,不必跟檔案目錄一一對應。大多數PHP Components都是根據PSR-4 autoloader standard來組織subnamespaces與檔案目錄的映射關係的。

從技術上來說,namespaces僅僅是一個PHP語言的符號,PHP解譯器使用這個符號來作為一組classes/interfaces/functions/constants集合的首碼,僅此而已。
Namespaces are important because they let us create sandboxed code that works alongside other developer's code. This is the cornerstone concept of the modern PHP component ecosystem. Helpful Tips

1. Multiple imports
bad:

<?phpuse Symfony\Component\HttpFoundation\Request,        Symfony\Component\HttpFoundation\Response,        Symfony\Component\HttpFoundation\Cookie;

good:

<?phpuse Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Cookie;

2. one class per file

3.Global namespace
如果我們引用一個沒有命名空間的class/interface/function/constant,PHP會首先假設這個class/interface/function/constant在當前的命名空間中。如果在當前命名空間中沒有找到,PHP才會開始resolve。而對於那些沒有沒有命名空間的代碼,PHP認為他們存在於global namespace。

PSR-4 Code to an interface

An interface is a contract between tow PHP objects that lets one object depend not on what another object is but, instead, on what another can do. Trait

A trait is a partial class implementation(i.e., constants, properties, and methods) that can be mixed into one or more existing PHP classes. Traits work double duty: they say what a class can do (like an interface), and they provide a modular implementation (like class).

相對Android開發,我最喜歡的iOS中一個特性就是category,PHP的trait就是有點類似於category,不過還是不太一樣的:
1. OC只能針對特定的類進行擴充,而PHP的trait可以將代碼單元注入到任意的不相關的類中;
2. 同時OC中的category並不能直接實現屬性的擴充,而PHP的trait則能實現常量,屬性,以及方法;
3. PHP的trait跟OC的category根本上來說用途是不一樣的,OC是對現存類直接擴充,不需要繼承實作類別。而PHP的trait需要在類的定義中使用 use 來明確。

跟class和interface的定義一樣,on trait per fileGenerators

Generators are easy to create because they are just PHP functions that use the yield keyword one or more times. Unlike regular PHP functions, generators never return a value. They only yield values.

這個概念並不陌生,Python包括Swift都有這個特性,可以用在對大量資料的迭代中,動態去擷取資料,而不是一次性產生,避免記憶體的浪費。

在每次迭代的過程中,PHP都會讓Generator執行個體計算和提供下一個迭代值。在這個過程中,當generator執行到yield value的時候,generator會暫停它的內部狀態的執行。只有generator被要求提供下一個迭代值的時候,它才會繼續它的內部狀態的執行。generator就這樣反覆pasuing 和 resuming,直到到達generator的函數定義的尾部或empty的時候,generator才會結束執行。

Generators are a tradeoff between versatility and simplicity. Generators are forward-only iterators. Closures

A closure is a function that encapsulates its surrounding state at the time it is created. The encapsulated state exists inside the closure even when the closure lives after it original environment ceases to exist.

這裡的閉包是指Closure和Anonymous functions。上面是作者對於閉包的解釋,感覺非常準確,比我看到的大多數解釋都要簡單清晰。閉包在日常業務開發中非常有用,可以非常方便替換我們經常需要用到的delegate設計模式,不需要再去定義一個interface,然後再實現這個interface,再把對應的對象指標傳遞過去。而是通過Closure,只需要簡簡單單傳遞一段代碼即可,這個極大簡化了日常業務開發。所以目前iOS開發中,大家通常都會使用block來代替delegate設計模式。

PHP Closure or Anonymous function 跟PHP function的定義文法是一樣的,但是實際上 Closure 的背後是Closure class的執行個體,所以Closure被認為是first-class value types。

Attach State : PHP的Closure不會automatically enclose application state,不像JavaScript/OC那樣會capture範圍之外的變數。而是,you must manually attach state to a PHP closure with the closure object's bindTo() method or the use keyword.

需要注意的是,PHP closures是objects。而我們之所以能讓一個closure 執行個體變數進行調用,是因為這個對象實現 __invoke() magic method,當我們在closure執行個體變數後面跟著一個 () 的時候,closure執行個體變數就會尋找並且調用__invoke() 方法,例如 $closure("Jason")。

同樣,由於PHP closure是objects。所以,在closure內部我們也可以通過 $this 訪問closure的各種內部狀態,但是這個狀態是非常boring。同時,closure的bindTo()方法可以有一些非常有趣的特殊用法,This method lets us bind a Closure object's internal state to a different object. The bindTo() method accepts an important second argument that specifies the PHP class of the object to which the closure is bound.This lets the closure access protected and private member variables of the object to which it is bound.。這個用法有點類似JavaScript的bind方法,可以改變Closure object的 $this 指標指向。

bindTo()這個有趣的用法,經常各種PHP架構的路由所採用,例如:

<? phpclass App{    protected $routes = array();    protected $responseStatus = '200 OK';    protected $responseContentType ='text/html';    protected $responseBody = 'Hello world';    public function addRoute($routePath, $routeCallback)    {        // 將Closure bind到App類上        $this->routes[$routePath] = $routeCallback->bindTo($this, __CLASS__);    }    public function dispatch($currentPath)    {        foreach ($this->routes as $routePath => $callback) {            if ($routePath === $currentPath) {                $callback();            }        }        // 這裡返回的state是在callback內修改過的        header('HTTP/1.1 '.$this.responseStatus);        header('Content-type: '.$this.responseContentType);        header('Content-length: '.mb_strlen($this->responseBody));        echo $this->responseBody;    }}// 添加註冊一個路由<?php$app = new App();$app->addRoute('/users/josh', function() {    // 因為這個route是bindTo到App class上的,所以這裡直接存取$this修改 App 的內部state    $this->responseContentType = 'application/json;charset=utf8';    $this->responseBody = '{"name": "Josh"}';});$app->dispatch('/users/josh');
Zend Opcache

從PHP 5.5.0開始,PHP引入了內建的bytecode cache支援,叫做 Zend OPcache。PHP解譯器在執行PHP指令碼的時候,會首先把PHP代碼編譯為Zend Opcodes (machine-code instructions),然後才會執行bytecode。在所有請求中,PHP解譯器都需要這樣處理所有的PHP檔案,read/parse/compiles,然而我們可以通過把PHP檔案預編為PHP bytecode來省略這個開銷,這就是Zend OPcache。

Zend OPcache的使用非常簡單,在我們配置之後,它就會在記憶體中自動緩衝precompiled PHP bytecode,在可用的情況就會直接執行這個PHP bytecode,而不需要再去編譯PHP代碼。

具體配置去google吧,有一點需要注意的是,如果同時配置了 Xdebug的話,在php.ini檔案中,需要在Xdebug之前載入Zend OPcache extension擴充。 Built-in HTTP server

PHP從5.4.0引入了內建的HTTP server,所以我們在不配置Apache或者nginx的情況下就直接預覽PHP程式。


Remember, the PHP built-in server is a web server. It speaks HTTP, and it can serve static assets in addition to PHP files. It's a great way to write and preview HTML locally without installing MAMP, WAMP, or a heavyweight web server.

要使用內建的HTTP server非常簡單,在工程的根目錄下,執行下面的命令即可:

php -S localhost:4000

如果要讓本網的其他裝置訪問PHP web server,我們可以這麼啟動:

php -S 0.0.0.0:4000

如果我們希望通過 PHP INI 設定檔去做一些特殊配置,可以通過下面命令來啟動:

php -S localhost:8000 -c app/config/php.ini

我們也可以通過Router Scripts來實現一些特殊的路由需求,可以通過下面的命令啟動:

php -S localhost:8000 router.php

在PHP代碼中,我們可以通過php_sapi_name()來判斷:

<?phpif (php_sapi_name() === 'cli-server') {        // PHP web server} else {        // Other web server}
Part 2. Good Pratices Standards PHP-FIG

PHP-FIG (PHP Framework Interop Group): The PHP-FIG is a group of PHP framework representatives who, according to the PHP-FIG website, "talk about the commonalities between our projects and find ways we can work together."

PHP-FIG是由很多不同PHP framework開發人員組成的一個開放組織,他們提出的recommendations,不是標準或也不是要求,更像是best pratices的建議集合。不過,目前比較流行大多是PHP架構,比如Laravel或Symfony,都遵守了這些recommendations,所以這個感覺更像是Modern PHP事實上的標準,如果要使用PHP的很多工具和龐大的各種開源庫,最好採用這個標準。

The PHP-FIG's mission is framework interoperability. And framework interoperability means working together via interfaces, autoloading, and style.
正如下面所說,PHP-FIG的使命就是不同framework之間的互連,讓不同架構可以很容易結合在一起使用。而實現互連目前主要通過三個方面來入手:interfaces, autoloading, style: Interfaces: Interfaces enable PHP developers to build, share, and use specialized components instead of monolithic frameworks,基於interfaces,我們可以做到直接使用某個架構的某個組件,比如Laravel的HTTP的處理部分就是直接使用 Symfony Frameworks的 symfony/httpfoundation 組件,而不用把整個Symfony都整合到Laravel之內。 Autoloading: PHP frameworks work together via autoloading. Autoloading is the process by which a PHP class is automatically located and loaded on-demand by the PHP interpreter during runtime,在autoloading標準出來之前,PHP組件和架構都是基於 \__autoload()或spl_autoload_register() 方法來實現自己獨特的autoloaders,所以我們要使用一個第三方組件的時候,需要首先去研究一下它的autoloaders的實現。 Style: PHP frameworks work together via code style. PSR

PSR是 PHP standards recommendation的縮寫,是PHP-FIG提出的recommendations文檔,例如PSR-1,PSR-2等。每個PHP-FIG recommendation都是為瞭解決某個大多數PHP架構開發中常遇到的問題而提出的。

目前在PHP-FIG的官方網站上,http://www.php-fig.org/psr/ ,可以看到所有的recommendations,目前被採用的有下面幾個:

具體的PSR文檔內容,可以參考官方網站,PSR-1/2/3/4 幾個文檔有中文翻譯:

文檔 原文 中文翻譯
PSR-1 Basic Coding Standard https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md https://segmentfault.com/a/1190000002521577
PSR-2 Coding Style Guide https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md https://segmentfault.com/a/1190000002521620
PSR-3 Logger Interface https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md https://segmentfault.com/a/1190000002521644
PSR-4 AutoLoading Standard https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md https://segmentfault.com/a/1190000002521658
PSR-1 Basic Coding standard

PHP tags : 使用 PSR-2 Strict Code Style

Implement PSR-1 : 要求必須採用PSR-1
Indentation: 採用4個空白字元作為縮排
Files and lines : 必須使用Unix linefeed(LF)作為結尾;檔案最後必須以空行作為結束;不能使用尾部 ?> PHP tag;每行盡量不要超過80個字元,最多不能超過120個字元;每行結尾不能包含空格;
Keywords: 所有的PHP關鍵字都必須小寫
Namespaces: 每個namespace聲明後面都必須跟著一個空行;使用use來import or alias namespaces的時候,必須在use聲明後面跟一個空行;
Classes: 定義類時,開始的大括弧(opening bracket)必須新起一行,結束的大括弧(closing bracket)必須在類體定義後面新起一行;extents/implements關鍵字必須跟在類名定義的後面;例如:

<?phpnamespace My\App;class Administrator extends User {    // Class definition body}

Methods: 方法定義的大括弧規則與類定義類似,opening brackets和closing brackets都必須新起一行。
Visibility: 對類中定義的全部property和method都必須聲明可見度(visibility),可見度是public, protected, private其中的一個;abstract / final 必須寫在visibility之前;static必須寫在visibility之後;
Control structures : 所有的control structure keyword (if/elseif/else/switch/case/while/do while/for/foreach/try/catch)的後面都必須一個Null 字元;大括弧的規則與class定義不同,opening brackets跟control structure keyword必須在同一行,而closing bracket必須另新一行;

我們可以通過IDE的格式化工具來讓代碼格式化,實現PSR-1和PSR-2的code style。我經常使用的工具PHPStorm就可以設定。還有一些其他工具,比如 PHP-CS-Fixer 或 PHP Code Sniffer PSR-3 Logger Interface

PSR-3 is an interface, and it prescribes methods that can be implemented by PHP logger components. PSR-4 Autoloaders

An autoloader is a strategy for finding a PHP class, interface, or trait and loading it into the PHP interpreter on-demand at runtime. PHP components and frameworks that support the PSR-4 autoloader standard can be located by and loaded into the PHP interpreter with only one autoloader.

關於PSR-4,看官方文檔之後感覺理解很困惑,本書的作者的解釋就非常簡潔:
The essence of PSR-4 is mapping a top-level namespaces prefix to a specific filesystem directory.,簡單來說,就是設定了一個namespaces首碼和某個特定的檔案目錄之間的映射關係,然後在這個namespace首碼之下如果還有更多的sub namespace,這些sub namespaces就會跟這個特定的目錄下面的子目錄一一映射起來。例如,\Oreilly\ModernPHP namespace與 src/ 實體路徑一一映射,那麼\Oreilly\ModernPHP\Chapter1對應的檔案夾就是src/Chapter1,而\Oreilly\ModernPHP\Chapter1\Example類對應的檔案路徑就是src/Chapter1/Example.php檔案。

PSR-4 lets you map a namespace prefix to a filesystem directory. The namespace prefix can be one top-level namespace. The namespace prefix can also be a top-level namespace and any number of subnamespaces. It's quite flexible. Components Components

Modern PHP is less about monolithic framework and more about composing solutions from specialized and interoperable components.

What Are Components?: A component is a bundle of code that helps solve a specific problem in your PHP application.

架構與Components:如果我們正在建立一個小項目,可以直接使用一些PHP Components集合來解決問題;如果我們進行中一個多人合作開發的大項目,我們可以通過使用一個Framework;但這都不是絕對的,應該根據具體問題來解決。

Packagist:跟其他語言的包管理機制一樣,例如Maven,也有一個網站 https://packagist.org/ 讓我們搜尋我們需要的PHP Components的相關資訊。總所周知的原因,Packagist在國內很不穩定,可以使用國內的全量鏡像來代替,http://www.phpcomposer.com/ 。 Composer

Composer is a dependency manager for PHP components taht runs on the command line,跟其他現代語言一樣,PHP使用Composer來做依賴管理,類似的有iOS中的Cocoapods,Android中的Maven/gradle,前端的npm,ruby的gem,這些工具可以大大簡化我們管理第三方庫的成本。於是,當我們在Packagist上面找到我們需要的Components之後,就可以通過Composer來使用這個庫。

當我們使用Composer來添加第三方Component的時候,Composer除了會自動幫我們下載需要的PHP Components之外,還會自動幫我們建立一個符合PSR-4的Autoloader。

跟Cocoapods類似,Cocoapods使用Podfile來指定需要依賴的第三方庫,以及儲存有當前使用的具體的第三方庫的版本號碼。所以我們需要把這兩個檔案都加入到版本控制中進行管理,確保不同成員/CI/開發環境等不同地方大家使用第三方庫版本的一致性。對應Composer中的檔案就是 composer.json以及composer.lock。這裡需要注意的是composer install 和 composer update 命令的差別:
* composer install,不會安裝比composer.lock中列出的更高版本的Components;
* composer update,會更新你的components到最新的穩定版,同時也會更新composer.lock檔案為最新的PHP components版本號碼。 Semantic Versioning

Modern PHP Components 使用 Semantic Versioning scheme,同時包含了用小數點(.)分隔的三個數字,比如 1.13.2。同時,這個也是很多其他語言開源庫的版本規則,對這個一直比較好奇,終於在Modern PHP中看到了相應的解釋。 major release number:第一個數字是major release number,只有當PHP Component發生不再向前相容的更新時,才需要增加這個版本號碼。 minor release number:第二個數字是minor release number,當PHP Component發生一些小的功能更新,並且沒有破壞版本相容時,增加這個版本號碼。 patch release number:最後一個數字是patch release number,當發生版本相容的bug修複的時候,增加這個版本號碼。 Create PHP Components

這部分跟iOS建立自己的spec非常相似,並不是非常複雜的問題,參考書或者官方文檔很容易就能發布

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.