在测试PHP中的特征时,我有点困惑为什么会引入特征。我做了一些小实验。首先,我直接在类
中调用trait方法<?php
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
}
class TheWorldIsNotEnough {
use HelloWorld;
public function sayHellos() {
$o = new HelloWorld();
$o->sayHello();
}
}
$o = new TheWorldIsNotEnough();
$o->sayHellos();
?>
我收到了错误
Fatal error: Cannot instantiate trait HelloWorld in C:\xampp\htdocs\test.php on line 35
但是当我这样做时
<?php
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
}
class MyHelloWorld {
use HelloWorld;
}
class TheWorldIsNotEnough {
use HelloWorld;
public function sayHellos() {
$o = new MyHelloWorld();
$o->sayHello();
}
}
$o = new TheWorldIsNotEnough();
$o->sayHellos();
?>
我能够调用特征方法并将结果显示为“Hello World!”。 那么使用Traits有什么好处呢?它与抽象类有什么不同?请帮助我理解使用方法。感谢。
答案 0 :(得分:7)
Traits
不应该被实例化。它们只是代码部分,您可以通过use
在类中重用它们。您可以想象,trait
代码会扩展并成为您班级的一部分。甚至令人伤心的是:
特质基本上是语言辅助的复制和粘贴。
所以你的例子应该是这样的:
<?php
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
}
class TheWorldIsNotEnough {
use HelloWorld;
public function sayHellos() {
// your trait defines this method, so now you can
// think that this method is defined in your class directly
$this->sayHello();
}
}
$o = new TheWorldIsNotEnough();
$o->sayHellos();
//or simply
$o->sayHello();
?>
答案 1 :(得分:1)
好的,这可能不是这样做的方法,但我想办法如何使用Traits以及为什么在某些情况下,对于我的项目来说它更好。它们是课程的一种延伸。如果您与CakePHP很常见,那些特征会让我想起控制器的模型或组件的行为。只需查阅: - )
一个抽象类略有不同,因为你可以像这样使用它来继承:
abstract class HelloWorld {
public function sayHello() {
echo "Hello World!";
}
abstract public function doFunnyStuff();
abstract public function doMoreFunnyStuff();
}
class ConcreteHelloWorld extends HelloWorld {
public function doFunnyStuff() {
echo "Funny Hello!";
}
public function doMoreFunnyStuff() {
echo "More Funny Hello!";
}
}
$o = new ConcreteHelloWorld();
$o->sayHello(); // common property
$o->doFunnyStuff(); // specialy implemented property
$o->doMoreFunnyStuff(); // specialy impelemented property
特质更像是一个类的扩展。我在MVC框架中使用Traits以这种方式扩展带有日志的类:
trait Logger
{
public function saveLog($kindOf, $messasge, $serverity)
{
some_connect_to_DB_pseudo_code();
$sqlQuery = "INSERT INTO log (kindof, message, serverity)
VALUES (".$kindof.", ".$message.", ".$serverity.")";
mysql_query($sqlQuery); // deprecated :-)
}
}
class Controller extends AppController
{
use Logger;
public function someAction($params)
{
$this->saveLog("CALL", __METHOD__." - started some Action with params: ".$params, 0);
...
...
}
}
它非常方便,因为我在每个类中使用它,并且我不必再次编写所有这些行,我必须连接到数据库并生成SQL查询。因为我通过整个MVC框架有很多继承,所以我不必将Logger作为一些父类包含在内。只需将“use”-keyword放入任何应该能够将loginfo发送到数据库的类中。
同样的事情对我来说对调试消息起作用我在这里写下这样的东西:
$this->debug("WARNING", $message);
我的Debug Trait正在制作一个格式良好的警告信息:-)希望它有助于理解。
答案 2 :(得分:1)
感谢所有发布答案的人,但我经过大量研究后得到了我真正想要的答案。我的问题是什么使得Traits与现有方法(如抽象类,继承等)的不同之处。它在类中调用时实例化的要点是正确的,但最大的区别是我们可以在类中包含多个特征
use class1, class2;
如果在两个类中存在相同的方法并且我们想要使用class2中的方法时发生冲突,我们就这样做
use class1, class2 {
class2::method1 insteadof class1;
}
即使是特征也可以通过这种方式定义多个特征:
trait Class1 {
use trait1, trait2;
}
与继承不同;如果特征具有静态属性,则使用该特征的每个类都具有这些属性的独立实例。 请检查此链接http://php.net/manual/en/language.oop5.traits.php#107965
traits vs inheritance的另一个不同之处是traits中定义的方法可以访问它们所使用的类的方法和属性,包括私有类。 http://php.net/manual/en/language.oop5.traits.php#109508
与接口实现不同,可以访问所有traits方法而无需再次定义它们。
答案 3 :(得分:0)
Abstract
和Trait
类之间唯一的共同点是,无法自行实例化a Trait/an Abstract
。
但他们的目的不同。 Trait
仅用于以细粒度和一致的方式对功能进行分组。它是通过使开发人员在生成不同类层次结构的几个独立类中reuse sets of methods freely
来减少单个继承的一些限制,其中Abstract
类只是提供一种模板来继承和强制继承类来实现抽象方法。