天天看點

努力成為一個優秀的PHP開發

作者:jay的實驗室
本文首發于GitBook.cn ,因超過一年的獨享期,可釋出于第三方平台。由于時間倉促,加之作者水準有限,有不足處,望廣大讀者包涵與指點。
努力成為一個優秀的PHP開發

語言特色

PHP确實是一門特色的語言(僅次于Python)

面向對象

自PHP5開始,PHP具有完整的對象模型,包括類,抽象類,接口,繼承,構造函數,反射,克隆和異常等。以下是PHP5.3-PHP7.2中關于面向對象的新特性:

  • 命名空間(PHP5.3,更好的組織類)
  • 性狀 (PHP5.4,解決了多繼承場景的問題)
  • 匿名類(PHP7.0)
  • 導入一組類(PHP7.0)
  • 類常量的可見性(PHP7.1)
  • 多異常捕獲處理 (PHP7.1)
  • 允許重寫抽象方法(PHP7.2)

函數式

與JAVA不同的是,PHP将函數視為"一等公民",如果你偏愛函數式程式設計的話,PHP也不會讓你失望。以下是PHP5.3-PHP7.2中關于函數式的新特性:

  • 閉包(PHP5.3)
  • 閉包支援$this(PHP5.4)
  • Closure::call() (PHP7.0)

異步程式設計

衆所周知,PHP是一門單線程同步語言。在PHP5.5之前,如果想要提高性能隻能通過多程序或者多線程(pthreads拓展)的方式來編寫代碼。但在PHP5.5官方推出的新特性Generator,異步成為了可能。以下是PHP5.3-PHP7.2中關于異步程式設計的新特性:

  • Generator(PHP5.5)

元程式設計

PHP 通過反射 API 和魔術方法,可以實作多種方式的元程式設計。例如可以通過魔術方法來模拟PHP缺失的面向對象特性-重載。以下是PHP5.3-PHP7.2中關于魔術方法的新特性:

  • __callStatic (PHP5.3)
  • __invoke() (PHP5.3)

PHP 标準庫

PHP标準庫提供了内置的資料結構、疊代器、接口、異常、函數、檔案處理。

資料結構

  • SplDoublyLinkedList 雙連結清單
  • SplStack 棧
  • SplQueue 隊列
  • SplHeap 堆
  • SplMaxHeap 最大堆
  • SplMinHeap 最小堆
  • SplPriorityQueue 優先隊列
  • SplFixedArray 固定數組
  • SplObjectStorage 對象容器

疊代器

  • AppendIterator 附加疊代器
  • ArrayIterator 數組疊代器
  • CachingIterator 緩存疊代器
  • CallbackFilterIterator — 回調過濾疊代器
  • DirectoryIterator — 目錄疊代器
  • EmptyIterator — 空疊代器
  • FilesystemIterator — 檔案系統疊代器
  • FilterIterator — 過濾疊代器
  • GlobIterator — Glob疊代器
  • InfiniteIterator — 無限疊代器
  • IteratorIterator — 疊代器疊代器
  • LimitIterator — 限定疊代器
  • MultipleIterator — 多重疊代器
  • NoRewindIterator — 無倒回疊代器
  • ParentIterator — 父疊代器
  • RecursiveArrayIterator — 遞歸數組疊代器
  • RecursiveCachingIterator — 遞歸緩存疊代器
  • RecursiveCallbackFilterIterator — 遞歸回調過濾疊代器
  • RecursiveDirectoryIterator — 遞歸目錄疊代器
  • RecursiveFilterIterator — 遞歸過濾疊代器
  • RecursiveIteratorIterator — 遞歸疊代疊代器
  • RecursiveRegexIterator — 遞歸正則疊代器
  • RecursiveTreeIterator — 遞歸樹狀結構疊代器
  • RegexIterator — 正則疊代器

接口

  • Countable —可計算接口
  • OuterIterator —外部疊代器接口
  • RecursiveIterator —遞歸疊代器接口
  • SeekableIterator —可查找疊代器接口

異常

  • BadFunctionCallException —錯誤函數調用異常
  • BadMethodCallException —錯誤方法調用異常
  • DomainException —作用域異常
  • InvalidArgumentException —非法參數異常
  • LengthException —長度異常
  • LogicException —邏輯異常
  • OutOfBoundsException —違背安全原則異常
  • OutOfRangeException —越界索引異常
  • OverflowException —上溢異常
  • RangeException —範圍異常
  • RuntimeException —運作時異常
  • UnderflowException —下溢異常
  • UnexpectedValueException —意外數值異常

函數

  • class_implements — 傳回指定的類實作的所有接口。
  • class_parents —傳回指定類的父類
  • class_uses —傳回指定類使用的性狀
  • iterator_apply —為疊代器中每個元素調用一個使用者自定義函數
  • iterator_count —計算疊代器中元素的個數
  • iterator_to_array —将疊代器中的元素拷貝到數組
  • spl_autoload_call —嘗試調用所有已注冊的__autoload()函數來裝載請求類
  • spl_autoload_extensions —注冊并傳回spl_autoload函數使用的預設檔案擴充名
  • spl_autoload_functions —傳回所有已注冊的__autoload()函數。
  • spl_autoload_register —注冊給定的函數作為 __autoload 的實作
  • spl_autoload_unregister — 登出已注冊的__autoload()函數
  • spl_autoload —__autoload()函數的預設實作
  • spl_classes — 傳回所有可用的SPL類
  • spl_object_hash —傳回指定對象的hash id

檔案處理

  • SplFileInfo —SplFileInfo類為單個檔案的資訊提供了高層次面向對象的接口。
  • SplFileObject —SplFileObject為檔案提供了一個面向對象接口。
  • SplTempFileObject —SplFileObject為臨時檔案提供了一個面向對象接口。

各種類及接口

  • ArrayObject —ArrayObject類允許對象作為數組使用
  • SplAbserver —SplAbserver 接口與SplSubject一起使用以實作觀察者設計模式。
  • SplSubject —SplSubject接口與SplObserver一起使用以實作觀察者設計模式。

最好的語言為何被怼

某MM:你能讓這個論壇的人都吵起來,我今晚就跟你走。 某軟體工程師:PHP是最好的語言! 某論壇真的就炸鍋了,各種吵架…… 某MM:服了你了,我們走吧,你想幹啥都行。 某軟體工程師:今天不行,我一定要說服他們,PHP必須是最好的語言……

程式設計語言的鄙視鍊中PHP總是被黑的最慘的那一個。但為什麼一部分人叫嚣着PHP是世界上最好的語言,而一部分人各種怼PHP呢?幾個原因:

學習門檻較低

由于屏蔽了記憶體管理,指針等比較複雜的語言特性以及類C的文法,PHP初學者可以很快的熟悉這門語言。動态語言的特性也使初學者感覺不到類型檢查。再加上非常容易搭建的運作環境,豐富的内置API,活躍的技術社群,這難道不是一個程式設計初學者眼中"世界上最好的語言"嗎?

當然這也是被黑的一個導火索,一個程式員居然不知道指針、異步IO、線程、鎖、枚舉、字典、泛型....。這還算是個程式員嗎?

曆史包袱

PHP不像大部分知名語言誕生于知名組織或公司。PHP起源于1995年,17歲的PHP之父(Rasmus Lerdorf)以Perl語言為基礎編寫了用來跟蹤與收集浏覽自己個人網站履歷資訊的服務端腳本。因為一開始主要功能是表單的轉換與資訊收集工作,是以這個服務端腳本被命名為Personal Home Page Tools/Form Interperter,簡稱PHP/FI。這就是PHP的命名的最初原因。 由于一開始PHP的初衷僅僅隻是一個工具而已,再加上Lerdorf盡管是個非常優秀的程式員,但是語言設計方面不是他所專長,導緻PHP的有非常多的曆史包袱。

  • 混亂的函數命名,Linux C風格與駝峰命名共存
  • 被誤用的字元串連接配接符(.)
  • 混亂的參數順序
  • 缺乏對多線程的支援

由于PHP始終如一的向下相容,PHP仍會背着這些包袱努力向前。

無知者的偏見

PHP确實如上述所說存在各種各樣的問題,但PHP社群與PHP的開發者們一直在努力着。然而有些無知者從未真正了解過PHP,甚至都沒有使用過,僅僅憑借某些社群論壇上一些跟風的言論就認定PHP是一門差勁的語言實在令人無奈。甚至我的某位大齡移動端同僚至今還認為PHP的變量命名是var。

規範還是規範

無規矩不成方圓,社會如此,團隊如此,工程如此。

從我們還很小的時候,爸媽就開始教育我們什麼可以做,什麼不可以做。比如"吃飯前要洗手","不能在公共場合大聲喧嘩"。等我們進入學校,乃至步入社會,我們明白總有各種條條款款限制着我們,可能是組織層面的,可能是道德層面的,也可能是法律層面的。我們要成為一個受他人尊重,被社會認可的人就必須堅守這些規範。

世界上沒有完美的事物,即使是再優秀的規範也不是完美的。好的規範可以減少人與人之間的協作成本但同時也會阻礙靈活性,如何把握規範限制的度值得推敲。

在沒有PSR規範之前,代碼命名,檔案命名,自動加載都沒有統一的标準,各個項目都自我約定規範或處于無規範狀态。後來PHPFIG為了實作元件的互操作性,并為實作最佳程式設計和測試實踐提供規範而制定了PSR規範。PHPFIG的成員包含了許多知名的開源項目作者,例如CakePHP作者,Composer作者,Drupal作者,Phalcon作者,Symfony作者,Yii作者等,詳細成員連結請點選此處。PSR并不是官方規範,然而衆多知名開源項目作者參與并制定使之成為PHP項目的事實規範。

PSR規範目前已有9個已實施的規範,8個處于草案階段的規範,1個被廢棄的規範共18個。以下是根據序号排列的規範:

  • PSR-0 自動加載規範 (已廢棄)
  • PSR-1 基礎編碼規範 (已實施)
  • PSR-2 編碼風格指南 (已實施)
  • PSR-3 日志接口 (已實施)
  • PSR-4 自動加載規範 (已實施)
  • PSR-5 PHPDOC标準 (草案)
  • PSR-6 緩存接口 (已實施)
  • PSR-7 HTTP消息接口 (已實施)
  • PSR-8 擁抱接口 (草案)
  • PSR-9 安全公告 (草案)
  • PSR-10 安全報告流程 (草案)
  • PSR-11 容器接口 (已實施)
  • PSR-12 拓展編碼風格指南 (草案)
  • PSR-13 超媒體連結 (已實施)
  • PSR-14 事件管理器 (草案)
  • PSR-15 HTTP中間件 (草案)
  • PSR-16 簡單緩存 (已實施)
  • PSR-17 HTTP工廠 (草案)

由于篇幅有限,隻講解已實施的規範

已實施的規範

PSR-1 基礎編碼規範

PSR-1僅僅隻對檔案,類與方法進行了規範。

  • 檔案必須隻使用<?php或者<?=
  • 檔案必須是無BOMUTF-8編碼
  • 檔案要不要不聲明類,方法,常量等,要不用來生成輸出,改變.ini設定等
  • 命名空間與類必須遵守PSR-4(PSR-0已廢棄)
  • 類名的命名格式必須是大駝峰,如:MyClass
  • 常量的命名格式必須是大寫+下劃線連結,如:MY_CONSTANTS
  • 方法的命名格式必須是小駝峰,如:myFunction

PSR-2 編碼風格指南

PSR-2是對PSR-1的拓展與延伸,在縮進,行的字元數限制,空格,空行,類與方法的可見性等方面進行了規範。

  • 代碼必須遵守PSR-1規範
  • 縮進必須是四個空格,而不能是TAB
  • 對行的字元數并沒有硬限制,但是軟限制在120個字元。建議80個字元以内。
  • 每個namespace命名空間聲明語句和 use聲明語句塊後面,必須插入一個空白行。範例如下:
namespace Vendor\Package;

use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;           
  • 類的開始花括号{必須在函數聲明後自成一行,結束花括号}也必須寫在函數主體後自成一行。範例如下:
//class declare
class Foo 
{
	//class body 
}           
  • 方法的開始花括号{必須在方法聲明後自成一行,結束花括号}也必須寫在方法主體後自成一行。範例如下:
class Foo 
{
	//method declare
    public function sampleMethod($a, $b = null)
    {
		//method body
    }
    
}           
  • 類的屬性和方法必須添加通路修飾符(private、protected 以及 public), abstract 以及 final 必須聲明在通路修飾符之前,而 static 必須聲明在通路修飾符之後。範例如下:
<?php
class Foo 
{
	//屬性前必須添加修飾符(private,protected,public)
	private $sampleProperty; 
	
	//方法前必須添加修飾符(private,protected,public)
    public function sampleMethod($a, $b = null)
    {
    }
	
	//abstract必須在通路修飾符前面
	abstract public function sampleAbstractMethod();
	
	//static必須聲明在通路修飾符後面
    final public static function sampleFinalStaticMethod()
    {
    }
}           
  • 控制結構的關鍵字後必須要有一個空格符,而調用方法或函數時則一定不能有。範例如下:
  • 控制結構的開始花括号{必須寫在聲明的同一行,而結束花括号}必須寫在主體後自成一行。範例如下:
  • 控制結構的開始左括号(後和結束右括号)前,都一定不能有空格符。範例如下:
class Foo
{
    public function sampleMethod($a, $b = null)
    {
        if ($a === $b) {
            bar();
        } elseif ($a > $b) {
            $foo->bar($arg1);
        } else {
            BazClass::bar($arg2, $arg3);
        }
    }           

PSR-3 日志接口

PSR-3定義了一個通用的日志接口,為了使日志類庫以簡單通用的方式,通過接收一個Psr\Log\LoggerInterface 對象,來記錄日志資訊。

實作了PSR-3規範的類庫

  • monolog

PSR-4 自動加載規範

PSR-4定義了關于由檔案路徑自動加載對應類的相關規範。

  • 此處的“類”泛指所有的class類、接口、traits可複用代碼塊以及其它類似結構。
  • 一個完整的類名需要具備 \<命名空間名>(\<子命名空間名>)*\<類名> 這種格式。完整的類名必須要有一個頂級命名空間,被稱為 "vendor namespace"完整的類名可以有一個或多個子命名空間完整的類名必須有一個最終的類名完整的類名中任意一部分中的下滑線都是沒有特殊含義的完整的類名可以由任意大小寫字母組成所有類名都必須是大小寫敏感的
  • 當加載對應完整類名的檔案時完整的類名中,去掉最前面的命名空間分隔符,前面連續的一個或多個命名空間和子命名空間,作為“命名空間字首”,其必須與至少一個“檔案基目錄”相對應緊接命名空間字首後的子命名空間必須與相應的”檔案基目錄“相比對,其中的命名空間分隔符将作為目錄分隔符末尾的類名必須與對應的以 .php 為字尾的檔案同名自動加載器(autoloader)的實作一定不能抛出異常、一定不能觸發任一級别的錯誤資訊以及不應該有傳回值

例子

下表展示了符合規範完整類名、命名空間字首和檔案基目錄所對應的檔案路徑。

完整類名 命名空間字首 基礎目錄 檔案路徑
\Acme\Log\Writer\File_Writer Acme\Log\Writer ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php
\Aura\Web\Response\Status Aura\Web /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php
\Symfony\Core\Request Symfony\Core ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php
\Zend\Acl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php

關于本規範的實作,可參考相關執行個體

PSR-6 緩存接口

緩存是提升項目性能的正常手段,同樣也是大多數架構或類庫的正常特性之一。這導緻不同的架構或類庫存在不同的級别的對于緩存的解決方案。這種差異使得開發人員不得不學習多個系統,甚至這些系統都不能提供給他們所需的功能。此外緩存庫的開發人員也在面臨一個抉擇:是隻支援少數的架構,還是編寫大量的擴充卡去适配各式各樣的系統。

PSR-6将解決這個問題,庫和架構開發人員可以指望緩存系統按照預期的方式工作,而緩存系統的開發人員隻需要實作一組接口,而不是一個完整的擴充卡。

PSR-7 HTTP消息接口

HTTP消息是Web開發的基礎。Web浏覽器和HTTP用戶端(如cURL)建立發送到Web伺服器的HTTP請求消息,它提供HTTP響應消息。伺服器端代碼接收HTTP請求消息,并傳回HTTP響應消息。

HTTP消息通常由終端使用者中抽象出來,但作為開發人員,我們通常需要知道它們是如何構造的,以及如何通路或操作它們以執行我們的任務,無論是對HTTP API請求,還是處理傳入請求。

每個HTTP請求消息都有特定的形式:

POST /path HTTP/1.1
Host: example.com

foo=bar&baz=bat
           

這個請求體的第一行是"請求行",依次包含了 HTTP請求方法,HTTP請求目标位址(通常是一個絕對URL或者web伺服器的路徑),HTTP的協定版本号。接下來是一個或多個HTTP頭,一個空行與消息内容。

HTTP響應内容有一個相似的結構

HTTP/1.1 200 OK
Content-Type: text/plain

This is the response body
           

第一行是"狀态行",依次包含了HTTP協定版本号,HTTP狀态碼與一個對狀态碼進行描述的"原因短語",與請求消息相似,接下來是一個或多個HTTP頭,一個空行與消息内容。

PSR-7規範就是對HTTP消息與構成它們的元素的抽象。

實作了PSR-7的類庫

  • guzzlehttp/psr7:
  • oscarotero/psr7-middlewares
  • zendframework/zend-diactoros

PSR-11 容器接口

PSR-11是依賴注入容器的通用接口,旨在規範架構或庫通過容器擷取對象與參數。

實作了PSR-11的類庫

  • PHP-DI/PHP-DI

PSR-13 超媒體連結

無論是HTML内容還是不同的API格式内容,超媒體連結正日益成為WEB重要的部分。然而,沒有單一的通用超媒體格式,也沒有一種通用的方式來表示格式之間的連結。

PSR-13旨在為PHP開發人員提供一種簡單、通用的、獨立于使用的序列化格式的方式來表示超媒體連結。進而允許系統将超媒體連結的響應序列化為一個或多個有線格式而獨立于決定這些連結應該是什麼的過程。

PSR-16 簡單緩存

PSR-16旨在規範一個用于緩存項和高速緩存驅動程式的簡單但可拓展的接口。

架構太多的痛苦

既然有語言之争,那麼架構之争也變得理所應當,作為一門專注于Web領域的語言,PHP有着太多的架構。有時候你是否會覺得學不完的架構很讓人苦惱?

我們先來看下有哪些主流架構(按照Github Star 降序排列)

Laravel

Laravel是目前PHP語言中最火的架構,沒有之一。以優雅為目标,用了許許多多php的新特性,活躍的社群,豐富的生态環境。最新LTS Laravel5.5 已經要求環境必須在php7.0以上了。可以說是PHP界最時尚的架構了。

Symfony

Symfony是爸爸級的架構,最強大的PHP架構。許許多多的知名開源項目基于Symfony,例如Laravel,Drupal,PHPBB。Symfony的元件化耦合性非常小,你完全可以單獨使用某一元件在你的項目中。

CodeIgniter

CI是老牌的PHP架構,上手簡單,文檔與案例非常豐富。但在特性上不夠豐富,沒有支援太多的PHP新特性。

Yii2

Yii2是一個全棧式的MVC架構,性能與可拓展性都非常好。

Phalcon

Phalcon是PHP界最快的MVC架構,采用Zend Extension的形式進行開發。然而由于對PHP開發而言太過黑盒,且開發難度較大,是以Phalcon團隊又開發出一門語言Zephir 來編寫Phalcon,大家可以嘗試一下。

Slim

Slim是一款麻雀雖小五髒俱全的架構,非常建議新手對其源碼進行研究。如果編寫小項目,采用Slim會非常的得心應手。

Cakephp

CakePHP在國内用的人數不是太多,但這并不影響作為老牌架構的地位。

Lumen

Lumen是一款專注于建構微服務架構和 API 應用的架構。

除了以上架構之外,還有鳥哥的Yaf,國産的ThinkPHP與PHP官方的Zend Framework也比較知名。

通用元件

Request

既然是HTTP項目,Request元件肯定必不可少,該元件封裝了請求的HTTP資訊。

相關的開源元件

  • Requests

Response

同上,HTTP項目不可或缺的元件,封裝了響應的HTTP資訊。

Router

Router元件主要用于路由分發,通過正則比對URL找到對應的控制器,執行個體化控制器并執行。

相關的開源元件

  • FastRoute
  • klein

Controller

Controller元件主要用于處理業務邏輯,并與Model元件或View元件進行互動。

Model

PHP的Model一般是充血模型,Modle元件封裝了具體的業務模型邏輯并實作了ORM,屏蔽了SQL細節,可以讓開發像操作對象一樣操作資料庫。

相關的開源元件

  • doctrine2
  • laravel-mongodb
  • Propel2

View

View元件一般是一個模闆引擎。

相關的開源元件

  • Twig
  • smarty

ErrorHander

ErrorHander元件主要用來捕獲異常與錯誤資訊并進行相關的處理。

相關的開源元件

  • collision

IOC Container

IOC Container 通過反射來解決類與類之間的依賴關系。

相關的開源元件

  • PHP-DI

沒有注釋是可恥的

當你進入一個新公司,或參與涉及到一個新項目時,是否會為項目沒有注釋而苦惱?

曾經問過公司的一個前輩,你為什麼不給代碼寫注釋呢?前輩說:“好的代碼是不需要注釋的"。在不去判斷前輩這句話的準确性,面對前輩寫的意大利面代碼,我也隻能攤手了。

這一章節,我們将探讨是否要寫注釋,注釋的作用以及PHPDoc在PHP項目中的運用。

是否要寫注釋?

不願意寫注釋的人有三種說辭:

  • 好的代碼不需要注釋
  • 壞的注釋會誤導讀者
  • 寫注釋太花費時間

對于第一種說辭,其實是強調代碼的自說明性,好的代碼會自己說話。然後在這個自說明僅僅強調了這個代碼的邏輯作用,卻無法附帶更多的資訊(在下面的注釋類型中會講解)。其次對于大部分并不能很好的書寫确切、精煉、自說明性的代碼的開發而言,這個言論更像是借口。

對于第二種說辭,是強調了錯誤注釋的危害而認為不應該寫注釋,這個邏輯就像是努力了可能沒結果是以不努力一樣。

對于第三種說辭,是強調了書寫注釋的成本太過高昂,然而對比不寫注釋帶來的溝通成本、再次閱讀了解的時間與精力成本而言,這點成本顯然是值得的。

注釋的作用

注釋不僅僅隻是為了解釋代碼,它還有其它的作用,以下是注釋的幾種作用:

重複代碼

重複性的注釋隻是把代碼用不同的文字再去描述一邊,除了給讀者增加閱讀量之外并沒有提供更多有用的資訊。

解釋代碼

解釋性注釋通常用來解釋複雜、歧義的代碼塊。通常是由于代碼含糊不清才會展現出這類注釋的價值。如果代碼是因為複雜才需要解釋的話,最好的方式是改進代碼,也就是前輩所說的"好的代碼不需要注釋"。

代碼标記

标記性的注釋并非有意留在代碼中的,它是用來提示開發者有些工作沒有完成。例如://todo。

概述代碼

概述代碼是把若幹行代碼用一兩句話概述,因為讀者讀注釋肯定比讀代碼快。概述性質的注釋對于那些要修改你代碼的人很有用。

代碼意圖說明

目的性注釋用來指明一段代碼的意圖,它指出要解決的問題而非解決的方法。

傳達代碼無法表述的資訊

某些資訊不能通過代碼來表示,但是又必須包含在源代碼中。這種注釋包括:

  • 版權聲明、版本号、作者等雜項資訊
  • 代碼設計相關的注意事項
  • 參考連結
  • 諸如PHPDoc,JavaDoc,JsDoc等編輯器要求有的注釋

對于完工的代碼,隻允許有三種注釋類型:代碼無法表述的資訊、目的性注釋與概述性注釋。

PHPDoc在PHP項目中的運用

PHPDoc(PSR-5)如上一小節所說,是為了傳達代碼無法表述的資訊。

@author

@author标記用來表明作者

文法

@author [name] [<email address>]           

描述

這個@author用來表明誰建立了這個結構元素**(指檔案、類、接口、性狀、方法、函數、常量、變量)**或者對它進行了重要的修改。此标記還可以包含電子郵件位址。

例子

/**
 * @author My Name
 * @author My Name <[email protected]>
 */           

@copyright

這個@copyright 标簽被用來記錄結構元素的版權資訊

文法

@copyright <description>           

描述

@copyright 定義了誰擁有"結構元素" 的版權資訊,除非另有說明,否則使用這個标記的版權适用于它應用的"結構元素"和它的子元素。

描述的格式受每個項目的編碼标準的控制。建議提及著作權和涉及的組織所涵蓋的年份。

例子

/**
 * @copyright 1997-2005 The PHP Group
 */           

@deprecated

@deprecated标記用于指明哪些“結構元素”被棄用,并在以後的版本中删除。

文法

@deprecated [<"Semantic Version">][:<"Semantic Version">] [<description>]           

描述

@deprecated聲明在将來的版本中将删除相關的“結構元素”,因為它已經過時或者不推薦使用它的用法。 這個标簽可以在版本号範圍内指定兩個版本号: 第一個版本号被稱為“起始版本”,它表示相關元素已經被棄用的版本。 第二個版本号被稱為“結束版本”,它表示關聯元素被計劃棄用的版本。

如果已經指定了“結束版本”,則相關的“結構元素”可能不再存在于“結束版本”中,并且可能在該版本或後續版本中被删除,但必須存在于所有先前版本中。

建議同時指定“開始版本”和“結束版本”。在這種情況下,兩個版本号必須由一個冒号(:)分隔,而中間沒有空格。 “開始版本”可能會被省略。在這種情況下,“結束版本”必須有一個冒号。

這個标記可能提供一個額外的描述,說明為什麼關聯的元素被棄用。

如果關聯的元素被另一個元素所取代,建議在指向新元素的“PHPDoc”中添加一個@see。

例子

/**
 * @deprecated
 *
 * @deprecated 1.0.0:2.0.0
 * @see \New\Recommended::method()
 *
 * @deprecated 1.0.0
 *
 * @deprecated :2.0.0
 *
 * @deprecated No longer used by internal code and not recommended.
 *
 * @deprecated 1.0.0 No longer used by internal code and not recommended.
 */           

@method

@method允許一個類知道哪些“魔法”方法是可調用的。

文法

@method [return type] [name]([type] [parameter], [...]) [description]           

描述

@method标記用于類包含__call()魔術方法并定義一些明确用途的情況。

有一個子類,它的父類有一個__call()來擁有動态的getter或setter來預定義的屬性。子類知道哪些getter和setter需要存在,但是卻依賴父類的__call()方法來提供它。在這種情況下,子類将為每個魔術setter或getter方法使用@method标記。

@method标記允許作者通過在簽名中包含這些類型來指定傳遞參數和傳回值的類型。

當預期的方法沒有傳回值時,可以省略傳回類型,在這種情況下預設傳回類型為void;。

@method标簽不能在沒有與類或接口相關聯的PHPDoc中使用。

例子

class Parent
{
    public function __call()
    {
        <...>
    }
}

/**
 * @method string getString()
 * @method void setInteger(int $integer)
 * @method setString(int $integer)
 */
class Child extends Parent
{
    <...>
}           

@param

@param标簽是用來指明函數或方法的參數

文法

@param ["Type"] [name] [<description>]           

描述

指明函數或方法的參數的類型和功能的時候可以使用@param 标記。當提供時,它必須包含一個“類型”來訓示預期的内容;另一方面,描述是可選的,但建議使用。對于複雜的結構,如選擇陣列,建議使用“内聯phpDoc”描述選項數組。

@param 可以有多行的描述,不需要明确的界定。

建議在每個函數和方法使用這個标記。

例子

/**
 * Counts the number of items in the provided array.
 *
 * @param mixed[] $items Array structure to count the elements of.
 *
 * @return int Returns the number of elements.
 */
function count(array $items)
{
    <...>
}           

下面的示例示範了用一個“内聯phpDoc”的來标記一個具有兩個元素:'required' 和 'label' 的可選數組。

/**
 * Initializes this class with the given options.
 *
 * @param array $options {
 *     @var bool   $required Whether this element is required
 *     @var string $label    The display name for this element
 * }
 */
public function __construct(array $options = array())
{
    <...>
}           

@property

@property标記用來讓一個類知道哪些“魔法”屬性存在。

文法

@property ["Type"] [name] [<description>]           

描述

當類包含__get()和__set()魔術方法,可以使用@property指定特定名稱。

有一個子類,它的父類有一個__get()。子類知道哪些屬性需要存在,但是依賴于父類的__get()方法來擷取它。在這種情況下,子類将為每個魔術屬性書寫一個@property标記。

@property标記不能在沒有類或者接口的“PHPDoc”中使用。

例子

class Parent
{
    public function __get()
    {
        <...>
    }
}

/**
 * @property string $myProperty
 */
class Child extends Parent
{
    <...>
}           

@return

@return 标記用來指明函數或方法的傳回值

文法

@return <"Type"> [description]           

描述

當指明函數或者方法的傳回值時可以使用@return,當使用@return的時候一定要包含"Type"來指定傳回什麼類型;另一方面的描述是可選的,但在複雜的傳回結構,如關聯數組時,是推薦的。

@return 标簽可能有一個多行描述,不需要顯式的限制。

建議在每個函數和方法中使用這個标記。唯一的例外是:正如任何一個項目的編碼标準所定義的那樣,函數與方法并沒有傳回值:這時@return可以省略。

例子

/**
 * @return int Indicates the number of items.
 */
function count()
{
    <...>
}

/**
 * @return string|null The label's text or null if none provided.
 */
function getLabel()
{
    <...>
}           

寫測試用例的開發就是迷人

作為最常見的改善項目品質的活動,測試一直是項目開發中的重要部分。

測試的級别

  • 單元測試:是将一個完整的類或者函數從完整的系統中隔離出來進行測試。
  • 內建測試:是對兩個或更多的類庫、類進行的聯合測試。這種測試通常在有了兩個可以測試的類就可以開始了,并且一直持續到系統開發完成。
  • 回歸測試:是指重複執行以前的測試用例,以便在原先通過了相同測試集合的軟體中查找缺陷。
  • 系統測試:是在最終的配置下運作整個軟體。以便測試安全、性能、資源消耗、時方面的問題以及其它無法在低級內建上測試的問題。

為什麼要寫測試用例

  • 更好的保障代碼品質
  • 避免重複性的測試,節省時間
  • 梳理業務邏輯

測試先行還是測試後行

有時候開發會很困惑,到底是先編寫測試用例還是編寫完代碼之後再編寫測試用例呢?答案是測試現行,原因如下:

  • 在寫代碼之前編寫測試用例并不會比寫代碼之後編寫測試用例花的時間更長。
  • 假設你首先編寫測試用例,你會更早的發現缺陷,更早的去修正他們。
  • 首先編寫測試用例會讓你更早的去思考需求與設計,更好的去編寫高品質代碼。
  • 在編寫代碼之前寫測試用例可以更早的暴露需求上的問題。

不寫測試用例的項目真的比寫測試用例的項目開發快嗎?

似乎大部分開發都意識到編寫測試用例對于項目開發的益處。然而對于時間成本的考量又是那些不願編寫測試用例的開發的顧慮所在。

那麼我們來思考編寫測試用例的作用—發現缺陷并修正,這個缺陷可能是需求上的,也可以是具體編碼上的。我們知道缺陷發現的越早,修正的成本(時間與精力)越低廉。需求上的缺陷導緻的成本又高于編碼上的缺陷。如果通過編寫測試用例來提早發現需求上的缺陷并修正,遠比項目即将傳遞時發現缺陷修正花費更少的時間。對比可能出現的返工或重新的需求修正與評估,編寫測試用例的花費的時間成本反而更少。

相關的測試架構

PHPUnit

PHPUnit是xUnit家族的一員,更是最有名的PHP測試架構。

Behat

Behat 是一款BDD(行為驅動測試)架構。

Codeception

Codeception是一款基于PHPUnit的現代全棧測試架構。受到BDD(行為驅動測試)的啟發,它提供了一種全新的方式去編寫驗收,功能甚至單元測試。

phpspec

phpspec同樣是一款BDD(行為驅動測試)架構。

同僚你好

三個臭皮匠頂得過一個諸葛亮,小公司可能靠某一個人,但一個公司想要做大,一定要看整個團隊的能力夠不夠強。

團隊對個人的情感影響

就仿佛有了一個安全的港灣,你可以在外面努力的闖蕩,但當你遇到問題時,遇到挫折時,團隊一定可以給予你精神上的鼓舞。

團隊對個人的能力性格上的補全

在團隊中每個人在技能、特長、知識、年齡、性格等方面具有互補性,你可以通過同僚的視角擷取一個不一樣的觀念來補全你能力上性格上的短闆。

朝着目标前進

每個團隊一定都會有一個既是團隊又是個人的目标,朝着這個目标努力的奮鬥的路途中學會信任,學會了解,學會犧牲。

方法論與 'X'DD

假設世界上有那麼一個人,他擁有無限的精力,最高的效率,最快的速度以及最完備的知識體系,那麼他做任何事的效率都是100%。然而世界上并沒有這麼一個人,但我們希望通過各自方法淬煉團隊,使團隊的工作效率無限趨向于這個人。

方法論

方法論是什麼?

方法論是一種以解決問題為目标的理論體系或系統,通常涉及對問題階段、任務、工具、方法技巧的論述。方法論會對一系列具體的方法進行分析研究、系統總結并最終提出較為一般性的原則。

軟體研發中的方法論

軟體研發是一門工程學,為了使團隊可以更高效更準确的完成某一個任務,許多前輩提出了以下幾種方法論。

  • 瀑布流開發
  • 疊代模型
  • 螺旋式開發
  • 靈活開發

瀑布流開發

瀑布流開發是一種序列化的開發方式。如下圖

努力成為一個優秀的PHP開發

特點:

  • 每個階段都是獨立且依賴于上一個階段
  • 文檔驅動
  • 易于組織,易于管理
  • 是一種嚴格線性的、按階段順序的、逐漸細化的開發模式

适用場景:

  • 産品路線明确,且技術方案成熟的項目
  • 比起開發效率更在乎品質的項目
  • 研發能力較弱時,采用瀑布式開發流程更容易把控

缺陷:

  • 項目初期,需求往往不明确,很難在初期就把需求敲定,影響後期環節
  • 開發過程中需産生大量文檔,增加工作量
  • 由于開發模型是線性的,使用者隻有等到整個過程的末期才能見到開發成果,進而增加了開發的風險。

疊代模型

疊代模型則是通過将大的需求拆建成一個個周期進行開發,以減少風險。如下圖,一個周期為一次疊代。

特點:

  • 不要求一次性地開發出完整的軟體系統,将軟體開發視為一個逐漸擷取用廣需求、完善軟體産品的過程
  • 降低風險,即使失誤損失的也隻是一次疊代周期的成本
  • 開發人員清楚問題的焦點所在,效率更高
  • 使用者需求無需一開始就完全界定

适用場景:

  • 需求難以确定、不斷變更的項目
  • 分析設計人員對應用領域很熟悉的項目
  • 使用者可不同程度地參與開發過程的項目

缺陷:

  • 對管理者的水準要求較高

螺旋模型

螺旋模型是一種演化軟體開發過程模型,它兼顧了快速原型的疊代的特征以及瀑布模型的系統化與嚴格監控。螺旋模型最大的特點在于引入了其他模型不具備的風險分析,使軟體在無法排除重大風險時有機會停止,以減小損失。同時,在每個疊代階段建構原型是螺旋模型用以減小風險的途徑。螺旋模型更适合大型的昂貴的系統級的軟體應用。

特點:

  • 設計上的靈活性,可以在項目的各個階段進行變更設計上的靈活性
  • 以小的分段來建構大型系統,使成本計算變得簡單容易
  • 客戶始終參與每個階段的開發,保證了項目不偏離正确方向以及項目的可控性。
  • 随着項目推進,客戶始終掌握項目的最新資訊 , 進而他或她能夠和管理層有效地互動。
  • 客戶認可這種公司内部的開發方式帶來的良好的溝通和高品質的産品。

适用場景

  • 大型的高風險項目
  • 新近開發,需求不明确的項目

靈活開發

靈活開發以使用者的需求進化為核心,采用疊代、循序漸進的方法進行軟體開發。在靈活開發中,軟體項目在建構初期被切分成多個子項目,各個子項目的成果都經過測試,具備可視、可內建和可運作使用的特征。換言之,就是把一個大項目分為多個互相聯系,但也可獨立運作的小項目,并分别完成,在此過程中軟體一直處于可使用狀态。

與其他三種模型不同,靈活開發更多的是闡述一種态度。

核心原則

  • 主張簡單
  • 擁抱變化
  • 你的第二個目标是可持續性
  • 遞增的變化
  • 令投資最大化
  • 有目的的模組化
  • 多種模型
  • 高品質的工作
  • 快速回報
  • 軟體是你的主要目标
  • 輕裝前進

宣言原則

我們歡迎需求的變化,即使在開發後期。靈活過程能夠駕馭變化,保持客戶的競争優勢。 經常傳遞可以工作的軟體,從幾星期到幾個月,時間尺度越短越好。 業務人員和開發者應該在整個項目過程中始終朝夕在一起工作。 圍繞鬥志高昂的人進行軟體開發,給開發者提供适宜的環境,滿足他們的需要,并相信他們能夠完成任務。 在開發小組中最有效率也最有效果的資訊傳達方式是面對面的交談。 可以工作的軟體是進度的主要度量标準。 靈活過程提倡可持續開發。出資人、開發人員和使用者應該總是維持不變的節奏。 對卓越技術與良好設計的不斷追求将有助于提高靈活性。 簡單——盡可能減少工作量的藝術至關重要。 最好的架構、需求和設計都源自自我組織的團隊。 每隔一定時間,團隊都要總結如何更有效率,然後相應地調整自己的行為

'X'DD

某某驅動開發,大家都聽說住,這個章節為大家講解最常見的驅動開發。

TDD

測試驅動開發(Test-driven development),是一種不同于傳統軟體開發流程的新型的開發方法。它要求在編寫某個功能的代碼之前先編寫測試代碼,然後隻編寫使測試通過的功能代碼,通過測試來推動整個開發的進行。這有助于編寫簡潔可用和高品質的代碼,并加速開發過程。

步驟

  1. 新增一個測試
  2. 運作所有的測試(有時候隻需要運作一個或一部分),發現新增的測試不能通過
  3. 做一些小小的改動,盡快地讓測試程式可運作,為此可以在程式中使用一些不合情理的方法
  4. 運作所有的測試,并且全部通過
  5. 重構代碼,以消除重複設計,優化設計結構

好處

  • TDD根據客戶需求編寫測試用例,對功能的過程和接口都進行了設計,而且這種從使用者角度對代碼進行的設計通常更符合後期開發的需求。因為關注使用者回報,可以及時響應需求變更,同時因為從使用者角度出發的簡單設計,也可以更快地适應變化。
  • 出于易測試和測試獨立性的要求,将促使我們實作松耦合的設計,并更多地依賴于接口而非具體的類,提高系統的可擴充性和抗變性。而且TDD明顯地縮短了設計決策的回報循環,使我們幾秒或幾分鐘之内就能獲得回報。
  • 将測試工作提到編碼之前,并頻繁地運作所有測試,可以盡量地避免和盡早地發現錯誤,極大地降低了後續測試及修複的成本,提高了代碼的品質。在測試的保護下,不斷重構代碼,以消除重複設計,優化設計結構,提高了代碼的重用性,進而提高了軟體産品的品質。
  • TDD提供了持續的回歸測試,使我們擁有重構的勇氣,因為代碼的改動導緻系統其他部分産生任何異常,測試都會立刻通知我們。完整的測試會幫助我們持續地跟蹤整個系統的狀态,是以我們就不需要擔心會産生什麼不可預知的副作用了。
  • TDD所産生的單元測試代碼就是最完美的開發者文檔,它們展示了所有的API該如何使用以及是如何運作的,而且它們與工作代碼保持同步,永遠是最新的。
  • TDD可以減輕壓力、降低憂慮、提高我們對代碼的信心、使我們擁有重構的勇氣,這些都是快樂工作的重要前提。
  • 快速的提高了開發效率

相關的PHP測試架構

  • phpunit

BDD

行為驅動開發(Behavior Driven Development)是一種靈活軟體開發的技術,它鼓勵軟體項目中的開發者、QA和非技術人員或商業參與者之間的協作。BDD最初是由Dan North在2003年命名,它包括驗收測試和客戶測試驅動等的極限程式設計的實踐,作為對測試驅動開發的回應。

與TDD不同的是,BDD并不是通過測試用例來規範限制開發者編寫出品質更高、bug更少的代碼,而是更加側重行為設計,來解決需求與開發脫節的問題。

步驟

  1. 需求方定義故事
  2. 開發編寫具體代碼
  3. 需求方檢視行為是否與故事比對
  4. 代碼重構與優化

優點

  • 避免需求方和開發者在溝通上的障礙,實作客戶和開發者同時定義系統的需求
  • 可以確定開發出來的産品更符合需求
  • 縮短開發階段結束之後的測試周期

DDD

領域驅動開發是一種通過将實作與不斷發展的模型相連接配接來實作複雜需求的軟體開發方法。

世界那麼大,我想去看看

計算機科學的範疇非常的龐大,身為開發的我們有時候卻不知道邊界有多大。古人有雲:不謀全局者,不足謀一域。計算機的世界那麼大,你想看看嗎?

計算機科學的主要領域(遵守ACM-2012計算分類系統)(By wiki)

大類 小類
電腦硬體 印刷電路闆 外部裝置 內建電路 超大規模內建電路 綠色計算 電子設計自動化
系統架構組織 計算機系統架構 嵌入式系統 實時計算
網絡 網絡傳輸協定 路由 網絡拓撲 網絡服務
軟體組織 解釋器 中間件 虛拟機 作業系統 軟體品質
軟體符号和工具 程式設計範型 程式設計語言 編譯器 領域特定語言 軟體架構 內建開發環境 軟體配置管理 庫
軟體開發 軟體開發過程 需求分析 軟體設計 軟體部署 軟體維護 開源模式
計算理論 自動機 可計算性理論 計算複雜性理論 量子計算 數值計算方法 計算機邏輯 形式語義學
算法 算法分析 算法設計 随機化算法 計算幾何
計算數學 離散數學 · 機率 · 統計學 · 數學軟體 · 數理邏輯 · 集合論 · 數論 · 圖論 · 類型論 · 範疇論 · 資訊論 · 數值分析 · 數學分析
資訊系統 資料庫管理系統 電腦資料 企業資訊系統 社會性軟體 地理資訊系統 決策支援系統 過程控制 資料挖掘 數字圖書館 系統平台 數字營銷 網際網路 資訊檢索
安全 密碼學 形式化方法 入侵檢測系統 網絡安全 資訊安全
人機互動 計算機輔助功能 · 使用者界面 · 可穿戴計算機 · 普适計算 · 虛拟現實 · 聊天機器人
并發性 并發計算 并行計算 分布式計算 多線程 多元處理
人工智能 自動推理 · 計算語言學 · 計算機視覺 · 進化計算 · 專家系統 · 自然語言處理 · 機器人學
機器學習 監督式學習 非監督式學習 強化學習 交叉驗證
計算機圖形學 計算機動畫 可視化 渲染 修飾照片 圖形處理器 混合現實 虛拟現實 圖像處理 圖像壓縮 實體造型
應用計算 電子商務 企業級軟體 計算數學 計算實體學 計算化學 計算生物學 計算社會科學 醫學資訊學 數字藝術 電子出版 網絡戰 電子遊戲 文字處理器 運籌學 教育技術學 生物資訊學 認知科學 檔案管理系統

價值觀

生命的長短以時間計算,生命的價值以貢獻計算 。

小而美

緻力于降低複雜度是軟體開發的核心。人的大腦并沒有辦法去管理那麼多的細節,但我們可以通過各自各樣的工具與理念去處理這種複雜度。無論是體系建構還是業務編碼,小而美一定是努力的方向。

自動化

高頻低價值的工作是需要交給機器幹的,我們需要做一些高杠杆,高附加值的工作。

創造世界

為什麼每一門語言一開始都會運作hello world?那是一個全新的世界在向你招手。想想你定義的變量,你定義的方法,你在以上帝的視角指定規則。就像"我的世界"一樣,你在創造一個全新的世界。唯一不同的是"我的世界"是用的像素塊,而你是用一種更進階更奇妙的方式去創造并享受其中。

繼續閱讀