特质,我如何使用它们来改进我的代码 (PHP)
特质,我如何使用它们来改进我的代码 (PHP)
用这 5 个技巧变得很棒
嗨,我是尼科,
我是伦敦(英国)一家票务经纪公司的高级工程师。
您正在从办公室阅读!
这是一个每天(几乎)发布的例程,我在其中记录我在办公室的日常生活中所从事的技术。
这篇文章是给谁看的?
在这篇文章中,您将了解 Traits、面向对象编程和继承。
如果你还没有到那里,不用担心,你可以从这个开始:
[
面向对象编程的完整指南
学习面向对象编程是 Web 开发人员可以学习的最有价值的技能之一。例如…
anastasionico.uk
](https://anastasionico.uk/blog/the-complete-guide-to-object-oriented-programming)
如果您想挑战自己的技能,请点击此处
[
领域驱动设计最快
让我对你做一点猜测,你来到这个网站并正在阅读这句话的原因是……
anastasionico.uk
](https://anastasionico.uk/blog/domain-driven-design-quickest-the-basics)
问题
如果您已经编写过面向对象的编程代码,那么您肯定会遇到诸如继承和接口之类的世界。
PHP 中的类不支持多重继承 , 接口帮助你处理这个问题。
给定一个类只能扩展一个父类,您被迫使用和实现尽可能多的接口来创建复杂的系统。
但,
如果您需要跨继承层次共享实现怎么办?
这就是特征出现的原因,现在我将向您解释如何使用它们。
考虑像抽象类这样的特征,它具有非常相似的结构,并且不能自行实例化。但是你可以将它合并到一个具体的类中。
特征定义的任何方法在使用它的类中自动可用。
实际上,
您应该将特征视为 INCLUDE,但对于类。
特质解决了什么问题?
作为一个高效的人,我喜欢记录我每天可以写多少字。
让我们想象一下,我开发了一个小应用程序,它可以为我计算它们并告诉我我是否做得很好,或者我是否必须更加努力。
假设我目前正在写这篇关于编程的文章和一本关于兽人、巫师和诸如此类的奇幻书。
我的项目有 2 节课:一门用于书本:
类图书写作
{ ... 公共函数 addWordsCount(int $todaysWords)
{
返回 $this->wordsCount += $todaysWords; }
公共函数 getHeroName(){...} ... }
和一个博客。
类文章写作
{ ... 公共函数 addWordsCount(int $todaysWords)
{
返回 $this->wordsCount += $todaysWords; }
公共函数 PostCategory(){...} ... }
你可以看到我的项目的代码库有一个很大的问题,
两种方法,看起来相同,做同样的事情,在两个类中,尽管相似,但彼此无关。
“重复可能是软件中万恶之源。”
—— Robert C. Martin,干净的代码集合
为什么是特质?
好吧,Traits 为这个问题提供了一个快速可靠(注意我没有说完美或优雅)的解决方案。
特质的目的是 封装该特定行为并使其可用于多个类 当他们需要的时候。
特质 CountWordsUtilityTrait
{
公共函数 addWordsCount(int $todaysWords)
{
返回 $this->wordsCount += $todaysWords;
}
}
此方法现在可以使用了。
类图书写作
{
使用 CountWordsUtilityTrait;
} 类文章写作
{
使用 CountWordsUtilityTrait;
}
两个类都可以使用 addWordsCount() 方法和以前一样,但现在它只在一个地方。
如果我们需要在 1 个月后更新代码,这是一个巨大的优势。
提示与技巧
使用多个特征
正如我们所说,我们拥有特征的原因之一是解决语言的单继承约束。
这意味着如果我们需要它,我们可以使用更多的特性。
PaginatorTrait
{
公共函数 getPageNumber(): int
{
返回 $this->pageNumber;
}
} 类图书写作
{
使用 CountWordsUtilityTrait、PaginatorTrait;
}
现在 写书 类可以访问 addWordsCount() 方法和 获取页码() 方法。
特征和接口
没人说 当一个类也实现了一个接口时,我们不能使用特征。
PHP 的限制只是针对我们要继承的类。
这意味着您实际上可以这样做:
类 ArticleWriting 实现 Commentable
{
使用 CountWordsUtilityTrait;
}
代替关键字
我已经在上面展示了我们可以在一个类中组合 2 个或更多特征,这很好,远离主域的功能更多。
当这些特征具有以相同方式调用的方法时,可能会出现一个问题。
我们的类或 PHP 引擎如何理解在每种情况下使用哪种方法?
对我来说,这尖叫着可能的错误。
出色地,
并不真地。
作为一名 PHP 开发人员,您可能已经遇到过该函数 实例 , 该语言还提供了另一个关键字,称为 代替 .
这个关键字让我们指定类应该如何在 trait 的方法之间进行选择。
下面是它的工作原理:
PaginatorTrait
{
公共函数 getPageNumber(): int
{
返回 $this->pageNumber;
}
} 特征 PublishedDataTrait
{
公共函数 getPageNumber(): int
{
返回 $this->publisher->getNumberOfPage();
}
} 类图书写作
{
使用 PaginatorTrait、PublishedDataTrait;
}
这将导致 PHP 致命错误,因为解释器不知道哪个 获取页码() 使用。
类图书写作
{
使用 PaginatorTrait, PublishedDataTrait {
PublishedDataTrait::getPageNumber instreadof PaginatorTrait;
}
}
有了那条线,您基本上是在说要使用 获取页码() 的方法 PublishedDataTrait 而不是 PaginatorTrait 的同名方法。
别名方法
如果你仔细阅读它,你现在可能会想出一个问题。
如果我们也想使用 PaginatorTrait::getPageNumber 怎么办?
记住,目标 插入 不是使用一种方法而不是另一种方法,
目标是避免冲突,从而避免我们代码中的致命错误。
解决方案非常简单。
我们所做的只是为剩余的函数创建一个别名。
类图书写作
{
使用 PaginatorTrait, PublishedDataTrait {
PublishedDataTrait::getPageNumber instreadof PaginatorTrait;
PaginatorTrait::getPageNumber 作为 getPaginatorPage
}
} $book = new BookWriting();
回声 $book->getPageNumber(); // 这指的是 PublishedDataTrait
echo $book->getPaginatorPage(); // 这是指 PaginatorTrait
请注意,给一个或另一个特征的方法起别名是不够的。
您需要首先指明优先级 代替。
准备好迎接当天的最后一个小技巧了吗?
使用别名更改访问修饰符
您已经了解了别名的工作原理,现在应该很清楚了。
别名也可以具有其他特殊功能。
它可以即时更改特征的访问修饰符。
让我们看看它是如何以及为什么重要的。
特征 PublishedDataTrait
{
公共函数 getPublisherId(): 字符串
{
返回 $this->publisher->getId();
}
} 类图书服务
{
使用 PublishedDataTrait {
PublishedDataTrait::getPublisherId 为私有
} 公共函数 getPublisherData()
{
返回 $this->getPublisherId()
}
} $book = new BookService();
回声 $book->getPublisherData(); // 这将返回 ID
回声 $book->getPublisherId(); // 这是一个错误:调用私有方法
特征被许多类使用,不仅相同的类处于同一级别。
其中一些可能会直接与控制器通信并提供诸如 ID 之类的合理详细信息。
通过指定访问修饰符(公共、受保护和私有之一),使用该特征的方法的类可以修改其行为。
为什么这很重要?
OOP 的开闭原则说对象应该对扩展开放但对修改关闭。换句话说,您应该能够在不更改模块的情况下更改模块的功能。在 OO 中,当您保持要扩展的代码不被修改时,可以最好地实现可扩展性。 — 鲍伯叔叔
不必担心在哪里调用一个类,因为它被设置为私有的,让我们的生活更轻松,让我们晚上睡得香
你怎么看?
你如何找到特质?
它是您经常使用的功能吗?
在下面的评论中写下您的想法。
结论
我已经做了将近十年的网络开发人员。
与位于伦敦市中心的世界级企业和屡获殊荣的营销机构合作。
此外,我还在博客和在线社区上撰写文章和教程。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明