Buggy CakePHP 代碼:CakePHP 開發人員最常犯的 6 個錯誤
已發表: 2022-03-11CakePHP 是一個了不起的 PHP 框架,但它有一個陡峭的學習曲線! 成為專家需要大量的研究和培訓。
我有幸使用 CakePHP 已經 7 年多了,在那段時間裡,我有幸與 CakePHP 社區的許多成員一起工作。
在這個 CakePHP 教程中,我想描述我多年來看到的一些不好的做法,並提出避免這些錯誤的正確方法。 這並不是說我的代碼是完美的,但作為一名程序員,我們一直在學習,所以遵循最佳實踐並在學習時進行調整非常重要!
本文內容的靈感來自於 CakeCoded 的一篇文章。 如果您想了解有關 CakePHP 的更多信息,請在此處訪問我們的學習部分。
常見錯誤 #1:不遵循 CakePHP 編碼約定
CakePHP 編碼約定可以在這裡查看。 我將強調一些我在查看其他程序員的代碼時經常注意到的事情。
控制結構。 你經常看到程序員犯了這個錯誤,並且在某些情況下會從其他編碼語言中引入實踐。 CakePHP 需要以下語法:
if ((expr_1) || (expr_2)) { // action_1; } elseif (!(expr_3) && (expr_4)) { // action_2; } else { // default_action; }
第一個括號之前應該有 1(一個)空格,最後一個括號和左括號之間應該有 1(一個)空格。 所以這意味著以下是不正確的:
if($this->request->data){ }
注意if
和(
以及)
和{
之間的間距
始終在控制結構中使用大括號,即使它們不是必需的。 它們增加了代碼的可讀性,並減少了邏輯錯誤。
因此,例如,以下內容是不正確的:
if ($foo) $bar = true
這應該是這樣的格式:
if ($foo) { $bar = true }
最後,注意放置括號的位置。 左括號不應開始新行。 並確保所有括號對齊,以便每個新括號與右括號對齊。
以下是一些不正確的例子:
if ($foo) { $bar = true; }
這是不正確的,左括號應該在第一行:
if ($foo) { $bar = true; if ($action) { $to = false; } }
縮進需要正確對齊。
我經常聽到程序員說,“但是我太忙了,沒時間整理代碼……” 我的回答是,“相信我,簡潔的代碼會經得起時間的考驗”。 如果您需要在幾個月內進行更改,那麼編寫不可讀的 CakePHP 代碼將是一場噩夢。
常見錯誤 #2:在 ORM 中不當使用可包含行為和遞歸級別
我最近有幸與 Facebook 的一位數據庫開發人員進行了非正式討論。 我們開始談論 CakePHP,他對我說,“哦,那使用 ORM 不是嗎? 這可能很可怕。” 我問他是什麼意思,他評論說使用對象關係映射 (ORM),SQL 查詢很容易變得不必要地大。
他在某種程度上是對的。 CakePHP 的部分魔力在於它對 ORM 的使用以及將不同的數據庫表關係組合在一起的方式。 默認情況下,CakePHP 會自動選擇任何相關的“屬於”、“有一個”和“有很多”數據,這會導致非常大的 SQL 查詢。 當您最初開發應用程序時,這些查詢可能不是問題,但在收集實時數據六個月後,您可能會發現應用程序變得非常緩慢,並且在某些情況下如果查詢未優化,則會崩潰。
在審核現有網站時,我會注意兩件事。 首先,是否更改了默認遞歸級別? 默認情況下,CakePHP 將遞歸級別設置為 1,在我看來這太高了。 我總是將其設置為 -1,然後使用可包含行為來獲取任何相關模型。
這導致了我要尋找的第二件事 - 是否使用了 Containable 行為? 我經常有新客戶來找我說 CakePHP 很慢。 原因幾乎總是因為 Containable 沒有被使用! 一個好的 CakePHP 程序員會優化他們的 SQL 查詢,不管幕後做了多少“自動魔術”。
直到 CakePHP 1.2 才添加可包含的行為,但是男孩有什麼不同嗎?! 確保盡可能多地使用可包含,因為它是優化 SQL 的有效方法。 有關如何實現和使用 Containable 行為的更多信息,請單擊此處。
常見錯誤 #3:將業務邏輯保留在控制器而不是模型中
好的 CakePHP 代碼將在模型文件中包含邏輯。 這需要一點時間來適應,但是一旦掌握了就沒有回頭路了! 控制器文件應該用於 MVC 模式中的用途 - 控制! 因此,使用您的控制器文件來處理用戶操作,同時讓業務邏輯進入模型文件。
一個很好的例子就是一個簡單的 CRUD - 一個日常動作! 讓我們以博客教程中的添加帖子功能為例。 默認添加函數如下:
public function add() { if ($this->request->is('post')) { $this->Post->create(); if ($this->Post->save($this->request->data)) { $this->Session->setFlash(__('Your post has been saved.')); return $this->redirect(array('action' => 'index')); } $this->Session->setFlash(__('Unable to add your post.')); } }
此控制器操作適用於簡單的添加,但如果您想做一些事情,例如在添加帖子時向管理員發送電子郵件,或者在添加帖子時更新另一個模型關聯,會發生什麼。 這是附加邏輯,但此邏輯不應進入我們的控制器文件。
相反,我們會在Post.php
模型中為此編寫一個函數。 也許是這樣的:
public function addPost($data = array(), $emailAdmin = true) { $this->create(); $this->save($data); // update any other tables // send the email to the admin user if ($emailAdmin) { } // if all is successful return true; }
然後,這將導致控制器操作發生小的更改,如下所示:
public function add() { if ($this->request->is('post')) { if ($this->Post->addPost($this->request->data)) { $this->Session->setFlash(__('Your post has been saved.')); return $this->redirect(array('action' => 'index')); } $this->Session->setFlash(__('Unable to add your post.')); } }
如您所見,新操作實際上少了一行,因為$this->Post->create()
已移至模型文件。

這是一個完美的日常示例,說明將邏輯移動到模型文件是一個好主意——而且它確實使代碼庫更加簡潔!
常見錯誤 #4:給代碼增加太多複雜性,而不是經常和儘早返回
這始終是一個持續的爭論,但是經常返回,並且早點返回確實可以使代碼看起來更清晰。 這比其他任何事情都更適用於模型方法。
但我到底是什麼意思? 好,我們來看看我們在上面的 CakePHP 教程中添加的方法:
public function addPost($data = array(), $emailAdmin = true) { $this->create(); $this->save($data); // update any other tables // send the email to the admin user if ($emailAdmin) { } // if all is successful return true; }
經常返回並提前返回意味著當我們運行我們的函數時,我們會定期檢查以確保一切正常。 如果不是,那麼我們返回 false,或者返回 CakePHP 錯誤。
用一個例子來說明這一點可能是最簡單的。 上面的函數有兩種寫法:
public function addPost($data = array(), $emailAdmin = true) { if ($data) { $this->create(); $result = $this->save($data); if ($result) { // update any other tables // send the email to the admin user if ($emailAdmin) { // send the admin email } } else { // problem saving the data return false; } // if all is successful return true; } else { // no data submitted return false; } }
看看代碼是如何迅速變得不可讀的? 到處都是if
和else
,函數很快就變成了一個大縮進。 不要誤會我的意思,我喜歡乾淨的縮進,但是如果經常使用 return 編寫函數,請注意函數的外觀,return early 原則。
public function addPost($data = array(), $emailAdmin = true) { if (!$data) { // no data submitted return false; } $this->create(); $result = $this->save($data); if (!$result) { // problem saving the data return false; } // update any other tables // send the email to the admin user if ($emailAdmin) { // send the admin email } // if all is successful return true; }
馬上,在這個小例子中,您可以看到代碼只有一個縮進並且更具可讀性。 邏輯實際上更有意義 - 讓邏輯逐行運行,如果一路有任何問題,返回錯誤並且不要繼續下一行。
這允許 CakePHP 程序員編寫與我們閱讀相同的方式——從左到右、從上到下閱讀代碼,而不是在不同的塊中,這很快就會讓人困惑!
常見錯誤 #5:不使用 DRY 原則
DRY 代表 Don't Repeat Yourself,它是在 CakePHP 中編碼時應該遵循的理念。 使用面向對象的代碼,沒有理由重複相同的代碼塊兩次!
以下是一些 CakePHP 技巧,可確保您不會重複自己:
如上所述,旨在將邏輯放入模型文件中,以便您可以共享邏輯。
在您的視圖文件中,如果您正在重複視圖,請將視圖代碼創建為元素,甚至是自定義助手。
設置一些配置設置 -
app/Config/bootstrap.php
文件是一個很好的地方。 這有助於確保您不會對應用程序名稱和主電子郵件地址等內容進行硬編碼。 您要做的最後一件事是瀏覽數百個文件,因為客戶要求更新應用程序中的電子郵件地址。總是問自己,“如果我重複代碼,有沒有更好的方法來編寫這段代碼,我把這段代碼放在正確的地方了嗎?” 如果您需要重複代碼,可能會寫得更好。
常見錯誤 #6:不評論代碼
我要說的最後一點是關於評論。 首先,文檔阻塞。 文檔塊是當您記錄方法或操作時。 只需要一分鐘的時間來記錄一下函數正在做什麼,但它在代碼的可讀性方面會產生如此大的差異。
CakePHP Doc Blocks 需要靠在頁面的左邊距。 這是一個使用上面代碼的簡單示例。
/** * Adds & saves a post as well as emails the admin to let them know the post has been added. * Also performs some saving to another table * * @param array $data The post data * @param bool $emailAdmin If set to true, will email the website admin * @return bool Returns true if successful */ public function addPost($data = array(), $emailAdmin = true) {
正如您將看到的,編寫一個 doc 塊並不需要很長時間,但它在代碼的壽命方面有很大的不同。 最終,這意味著代碼可以在你作為開發人員之後繼續存在。
內嵌註釋也是如此。 不要害怕解釋你的代碼在做什麼以及為什麼! 從長遠來看,它使您更容易理解您的代碼,尤其是當其他開發人員正在查看它時!
包起來
CakePHP 是一個擴展的、功能齊全的框架。 鑑於它遵循約定優於配置,CakePHP 比其他基於 PHP 的框架更嚴格,從某種意義上說,用戶被“強制”遵循某種佈局代碼的方式。 這可能會引起爭議,但根據我的經驗,它會導致代碼庫更加一致、可讀和易於理解——而不是讓開發人員“選擇”代碼應該如何編寫,開發團隊將通過遵循 Cake 的約定來編寫一致的代碼.
通過遵循此 CakePHP 教程並確保您的代碼編寫良好,應用程序可以經受住時間的考驗。 代碼應該總是為明天而寫——這樣如果另一個開發人員在幾年後查看特定的代碼塊,他就會理解代碼,並堅持預期的標準。 CakePHP 也不例外,希望本指南能幫助糾正一些壞習慣。