作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
CakePHP是一个了不起的PHP框架,但它有一个陡峭的学习曲线! 要成为专家需要大量的研究和训练.
我很幸运地使用CakePHP超过7年了, 在这段时间里,我有幸与许多人一起工作 CakePHP社区的成员.
在这个CakePHP教程中,我想描述一些我多年来看到的糟糕实践, 并提出避免这些错误的正确方法. 这并不是说我的代码是完美的, 但作为一名程序员,我们总是在学习, 因此,遵循最佳实践并在学习过程中进行调整非常重要!
这篇文章的内容是受一个帖子的启发 CakeCoded. 如果您想了解更多关于CakePHP的信息,请访问我们的学习部分 here.
CakePHP的编码约定可以 看这里. 我将强调一些我在查看其他程序员的代码时经常注意到的事情.
控制结构. 所以你经常会看到程序员犯这个错误, 在某些情况下,还会引入其他编码语言的实践. CakePHP期望以下语法:
If ((expr_1) || (expr_2)) {
/ / action_1;
} elseif (!(expr_3) && (expr_4)) {
/ / action_2;
} else {
/ / default_action;
}
第一个括号前应该有1(1)个空格,最后一个括号和左括号之间应该有1(1)个空格. 因此,这意味着以下内容是不正确的:
if($this->request->data){
}
的空格 if
and (
,以及 )
and {
在控制结构中总是使用花括号,即使不需要. 它们增加了代码的可读性,并且减少了逻辑错误.
因此,例如,以下是不正确的:
如果($ foo)
$bar = true
应该这样格式化:
If ($foo) {
$bar = true
}
最后,注意括号的位置. 左括号不应该开始新的一行. 确保所有的括号对齐,使每个新括号与结束括号对齐.
下面是一些不正确的例子:
如果($ foo)
{
$bar = true;
}
这是不正确的,左括号应该在第一行:
If ($foo) {
$bar = true;
If ($action) {
$to = false;
}
}
缩进需要正确对齐.
我经常听到程序员说:“但是我太忙了,没时间把代码写得整洁…….我的回答是:“相信我,整洁的代码经得起时间的考验。”. 如果需要在几个月内进行更改,那么编写不可读的CakePHP代码将是一场噩梦.
最近,我有幸与Facebook的一位数据库开发人员进行了一次非正式的讨论. 我们开始谈论CakePHP,他对我说,“哦,它使用ORM,不是吗? 这很可怕.我问他是什么意思, 他评论说,使用对象关系映射(ORM)很容易使SQL查询变得不必要的大.
在某种程度上他是对的. CakePHP的神奇之处在于它对ORM的使用,以及它将不同的数据库表关系组合在一起的方式. 默认情况下, CakePHP自动选择任何相关的“属于”, “有一个”和“有很多”数据, 这可能导致非常大的SQL查询. 在最初开发应用程序时,这些查询可能不是一个问题, 但经过六个月的实时数据收集, 您可能会发现应用程序变得非常慢, 在某些情况下,如果查询没有优化就会崩溃.
在审核一个现有网站时,我注意两件事. 首先,是否更改了默认递归级别? 默认情况下,CakePHP将递归级别设置为1,我认为这个级别太高了. 我总是将其设置为-1,然后使用containable行为来获取任何相关模型.
这就引出了我要寻找的第二件事——是否使用了Containable行为? 我经常有新客户来找我,说CakePHP很慢. 原因几乎总是因为Containable还没有被使用! 一个优秀的CakePHP程序员会优化他们的SQL查询,而不管幕后做了多少“自动魔术”.
直到CakePHP 1才添加了可包含的行为.2 .但是,男孩,这有什么不同?! 确保尽可能多地使用containable,因为这是优化SQL的有效方法. 有关如何实现和使用Containable行为的详细信息,请参见 点击这里.
好的CakePHP代码将在模型文件中包含逻辑. 这需要一点时间来适应,但一旦掌握了就没有回头路了! 控制器文件应该用于它在MVC模式中的目的——控制! 所以使用你的控制器文件来处理用户动作, 同时让业务逻辑进入模型文件.
一个很好的例子就是一个简单的CRUD——一个日常操作! 让我们以博客教程中的添加帖子函数为例. 默认的add函数如下:
公共函数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
model. 也许是这样的:
公共功能addPost($data = array(), $emailAdmin = true) {
$this->create();
$this->save($data);
//更新其他表
//发送邮件给admin用户
if ($emailAdmin) {
}
//如果一切成功
返回true;
}
这将导致对控制器动作的一个小改变,如下所示:
公共函数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()
是否已移动到模型文件.
这是一个完美的, 在日常示例中,将逻辑移动到模型文件中是一个好主意——而且它肯定会使代码库更加清晰!
这一直是一个持续的争论, 但是经常回来, 提前返回当然会使代码看起来更干净. 这一点更适用于模型方法.
但我到底是什么意思? 好吧,让我们看看我们在上面的CakePHP教程中添加的方法:
公共功能addPost($data = array(), $emailAdmin = true) {
$this->create();
$this->save($data);
//更新其他表
//发送邮件给admin用户
if ($emailAdmin) {
}
//如果一切成功
返回true;
}
经常回来, 提前返回意味着当我们运行函数时, 我们定期检查以确保一切正常. 如果不是,则返回false,或者返回CakePHP错误.
用一个例子来说明这一点可能是最简单的. 上面的函数有两种写法:
公共功能addPost($data = array(), $emailAdmin = true) {
If (元数据){
$this->create();
$result = $this->save($data);
If (结果美元){
//更新其他表
//发送邮件给admin用户
if ($emailAdmin) {
//发送admin邮件
}
} else {
//保存数据有问题
返回错误;
}
//如果一切成功
返回true;
} else {
//没有数据提交
返回错误;
}
}
看看代码是如何迅速变得不可读的? 有 if
s and else
S到处都是,函数很快就变成了一个大缩进. 别误会我, 我喜欢干净的凹痕, 但是,如果经常使用return来编写函数,请注意它是什么样子的, 早退原则.
公共功能addPost($data = array(), $emailAdmin = true) {
if (!元数据){
//没有数据提交
返回错误;
}
$this->create();
$result = $this->save($data);
if (!结果美元){
//保存数据有问题
返回错误;
}
//更新其他表
//发送邮件给admin用户
if ($emailAdmin) {
//发送admin邮件
}
//如果一切成功
返回true;
}
马上, 在这个小例子中, 您可以看到代码只有一个缩进,可读性更强. 逻辑实际上更有意义——让逻辑逐行运行, 如果在此过程中出现任何问题, 返回错误,不要继续下一行.
这允许CakePHP程序员用和我们阅读一样的方式来写代码——从左到右读代码, 从上到下, 而不是在不同的街区, 哪个很快就会让人困惑!
DRY代表不要重复自己, 这是在CakePHP中编写代码时应该遵循的哲学. 对于面向对象的代码,没有理由重复相同的代码块两次!
这里有一些CakePHP技巧,可以确保你不会重复自己:
如上所述,目标是将逻辑放入模型文件中,以便您可以共享逻辑.
在视图文件中, 如果你在重复视图, 将视图代码创建为一个元素, 甚至是一个定制的助手.
设置一些配置设置 应用程序/配置/引导.php
文件是一个很好的地方. 这有助于确保您没有硬编码诸如应用程序名称和主电子邮件地址之类的内容. 您最不希望做的事情就是仅仅因为客户端要求更新应用程序中的电子邮件地址而遍历数百个文件.
经常问自己, “如果我在重复代码, 是否有更好的方法来编写这段代码, 我把代码放对地方了吗?很有可能,如果你需要重复代码,它可以写得更好.
我想说的最后一点是关于评论. 首先,文档阻塞. 文档块是当你记录一个方法或一个动作的时候. 只需要花一分钟的时间来记录一下函数正在做什么, 但是它在代码的可读性方面有很大的不同.
CakePHP文档块需要对着页面的左边距. 这是一个使用上面代码的简单示例.
/**
* Adds & 保存帖子,并发送电子邮件给管理员,让他们知道帖子已添加.
*也执行一些保存到另一个表
*
* @param array $data post data
@param bool $emailAdmin如果设置为true,将发送电子邮件给网站管理员
* @return bool如果成功返回true
*/
公共功能addPost($data = array(), $emailAdmin = true) {
你会看到, 编写文档块并不需要很长时间, 但这对代码的寿命有很大的影响. 最终,这意味着代码可以在你作为开发人员之后继续存在.
内联注释也是如此. 不要害怕解释你的代码在做什么和为什么! 从长远来看,它使理解代码变得容易得多, 尤其是当其他开发者也在关注它的时候!
CakePHP是一个功能全面的框架. 假设它遵循约定而不是配置, CakePHP比其他基于PHP的框架更严格, 从某种意义上说,用户被“强迫”遵循某种布局代码的方式. 这是有争议的, 但在我的经验中,它导致了一个更一致的代码库, 可读性和可理解性——而不是让开发人员“选择”应该如何编写代码, 开发团队将按照Cake的约定编写一致的代码.
通过遵循本CakePHP教程并确保您的代码编写得很好, 应用程序可以经受时间的考验. 代码应该永远是为明天而写的——这样,如果另一个开发人员在几年后看到一个特定的代码块, 他会理解代码的, 并坚持预期的标准. CakePHP也不例外,希望本指南能帮助纠正一些坏习惯.
世界级的文章,每周发一次.
世界级的文章,每周发一次.