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 也不例外,希望本指南能帮助纠正一些坏习惯。
