为什么Traits不能直接实例化?
Why Traits cannot be instantiated directly?
在 PHP 中测试特征时,我有点困惑为什么要引入特征。我做了一些小实验。首先我直接在 class
中调用了 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();
?>
我能够调用 trait 方法并显示结果 "Hello World! "。
那么使用 Traits 的优势是什么?它与抽象 classes 有何不同?请帮助我了解用法。谢谢
Abstract
和 Trait
class 之间唯一的共同点是无法单独实例化 a Trait/an Abstract
。
但他们的目的不同。 Trait
仅旨在以细粒度和一致的方式对功能进行分组。它通过使开发人员能够 reuse sets of methods freely
生活在不同 class 层次结构中的几个独立 class 中来减少单一继承的一些限制,其中 Abstract
class 是只是为了提供一种模板来继承并强制继承class实现抽象方法。
Traits
不应该被实例化。它们只是代码部分,您可以通过 use
ing 在 classes 中重用它们。您可以想象,trait
代码扩展并成为您的 class 的一部分。更让人难过的是:
Traits are essentially language assisted copy and paste.
所以你的例子应该是这样的:
<?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();
?>
好的,这可能不是解决问题的方法,但我想出了一种方法来说明如何使用 Traits 以及为什么它在某些情况下对我的项目更好。它们是 classes 的一种扩展。如果您对 CakePHP 很熟悉,那么这些 Traits 让我想起了模型的行为或控制器的组件。查一下:-)
抽象 class 略有不同,因为您可以像这样将其用于继承:
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
特质更像是class的延伸。我在 MVC 框架中使用 Traits 来扩展 classes 以这种方式进行日志记录:
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);
...
...
}
}
它非常方便,因为我在每个 class 中都使用它,而且我不必在必须连接到数据库并生成 SQL 查询的地方再次编写所有这些行。而且由于我在整个 MVC 框架中有很多继承,所以我不必将 Logger 作为某些父项包含在内 class。只需将它与 "use"-关键字一起放入任何应该能够将登录信息发送到数据库的 class。
同样的事情对我来说适用于调试消息,我只是写了这样的东西:
$this->debug("WARNING", $message);
我的 Debug Trait 正在制作格式良好的警告消息 :-) 希望它有助于理解。
感谢所有发布答案的人,但我真正寻找的答案是经过大量研究后得到的。我的问题是什么使 Traits 不同于抽象 class、继承等现有方法。在 class 内部调用时实例化的要点是可以的,但最大的区别是我们可以在其中包含多个特征class这样
use class1, class2;
如果 classes 中存在相同的方法而我们想使用 class2 中的方法,我们会这样做
use class1, class2 {
class2::method1 insteadof class1;
}
甚至 traits 也可以有多个这样定义的 traits:
trait Class1 {
use trait1, trait2;
}
不同于继承;如果特征具有静态属性,则使用该特征的每个 class 都具有这些属性的独立实例。
检查这个 link http://php.net/manual/en/language.oop5.traits.php#107965
特征与继承的另一个区别是,特征中定义的方法可以访问 class 使用它们的方法和属性,包括私有方法和属性。 http://php.net/manual/en/language.oop5.traits.php#109508.
与接口实现不同的是,无需再次定义所有特征方法即可访问。
在 PHP 中测试特征时,我有点困惑为什么要引入特征。我做了一些小实验。首先我直接在 class
中调用了 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();
?>
我能够调用 trait 方法并显示结果 "Hello World! "。 那么使用 Traits 的优势是什么?它与抽象 classes 有何不同?请帮助我了解用法。谢谢
Abstract
和 Trait
class 之间唯一的共同点是无法单独实例化 a Trait/an Abstract
。
但他们的目的不同。 Trait
仅旨在以细粒度和一致的方式对功能进行分组。它通过使开发人员能够 reuse sets of methods freely
生活在不同 class 层次结构中的几个独立 class 中来减少单一继承的一些限制,其中 Abstract
class 是只是为了提供一种模板来继承并强制继承class实现抽象方法。
Traits
不应该被实例化。它们只是代码部分,您可以通过 use
ing 在 classes 中重用它们。您可以想象,trait
代码扩展并成为您的 class 的一部分。更让人难过的是:
Traits are essentially language assisted copy and paste.
所以你的例子应该是这样的:
<?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();
?>
好的,这可能不是解决问题的方法,但我想出了一种方法来说明如何使用 Traits 以及为什么它在某些情况下对我的项目更好。它们是 classes 的一种扩展。如果您对 CakePHP 很熟悉,那么这些 Traits 让我想起了模型的行为或控制器的组件。查一下:-)
抽象 class 略有不同,因为您可以像这样将其用于继承:
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
特质更像是class的延伸。我在 MVC 框架中使用 Traits 来扩展 classes 以这种方式进行日志记录:
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);
...
...
}
}
它非常方便,因为我在每个 class 中都使用它,而且我不必在必须连接到数据库并生成 SQL 查询的地方再次编写所有这些行。而且由于我在整个 MVC 框架中有很多继承,所以我不必将 Logger 作为某些父项包含在内 class。只需将它与 "use"-关键字一起放入任何应该能够将登录信息发送到数据库的 class。
同样的事情对我来说适用于调试消息,我只是写了这样的东西:
$this->debug("WARNING", $message);
我的 Debug Trait 正在制作格式良好的警告消息 :-) 希望它有助于理解。
感谢所有发布答案的人,但我真正寻找的答案是经过大量研究后得到的。我的问题是什么使 Traits 不同于抽象 class、继承等现有方法。在 class 内部调用时实例化的要点是可以的,但最大的区别是我们可以在其中包含多个特征class这样
use class1, class2;
如果 classes 中存在相同的方法而我们想使用 class2 中的方法,我们会这样做
use class1, class2 {
class2::method1 insteadof class1;
}
甚至 traits 也可以有多个这样定义的 traits:
trait Class1 {
use trait1, trait2;
}
不同于继承;如果特征具有静态属性,则使用该特征的每个 class 都具有这些属性的独立实例。 检查这个 link http://php.net/manual/en/language.oop5.traits.php#107965
特征与继承的另一个区别是,特征中定义的方法可以访问 class 使用它们的方法和属性,包括私有方法和属性。 http://php.net/manual/en/language.oop5.traits.php#109508.
与接口实现不同的是,无需再次定义所有特征方法即可访问。