php 为什么Traits不能直接示例化?

q9yhzks0  于 2023-11-16  发布在  PHP
关注(0)|答案(4)|浏览(144)

在PHP中测试trait的时候,我有点困惑为什么要引入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!“。那么使用Trait的好处是什么?它与抽象类有什么不同?请帮助我理解用法。谢谢。

56lgkhnf

56lgkhnf1#

Traits不应该被示例化。它们只是代码部分,你可以通过use ing它们在你的类中重用。你可以想象,一个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();
?>

字符串

yduiuuwa

yduiuuwa2#

感谢所有贴出答案的人,但我真正在寻找的答案是我在大量研究后得到的。我的问题是是什么使Traits不同于现有的方法,如抽象类,继承等。在类内部调用时示例化它是可以的,但最大的区别是我们可以通过这种方式在类中包含多个trait

use class1, class2;

字符串
在冲突的情况下,当两个类中存在相同的方法时,我们想使用class2中的方法,我们这样做

use class1, class2 {
  class2::method1 insteadof class1;
}


即使是traits也可以有多个traits以这种方式定义:

trait Class1 {
    use trait1, trait2;
}


与继承不同,如果trait具有静态属性,则使用该trait的每个类都具有这些属性的独立示例。http://php.net/manual/en/language.oop5.traits.php#107965
traits与继承的另一个区别是,traits中定义的方法可以访问它们所使用的类的方法和属性,包括私有方法和属性。http://php.net/manual/en/language.oop5.traits.php#109508
与接口实现不同的是,所有traits方法都可以访问,而无需再次定义它们。

8fq7wneg

8fq7wneg3#

好吧,这可能不是实现它的方法,但我找到了一种方法来使用Traits,以及为什么在某些情况下它对我的项目更好。它们是类的一种扩展。如果你经常使用CakePHP,这些Traits让我想起了模型的行为或控制器的组件。只要查找一下:-)
抽象类略有不同,因为你可以像这样使用它来继承:

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

字符串
trait更像是类的扩展。我在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”-关键字一起放置到任何应该能够将loginfo发送到数据库的类中。
同样的事情也适用于我的调试消息,我只是写这样的东西:

$this->debug("WARNING", $message);


我的座右铭是:“善有善报,恶有恶报”。

0sgqnhkj

0sgqnhkj4#

AbstractTrait类之间唯一的共同点是,不可能单独示例化a Trait/an Abstract
但它们的目的是不同的。Trait只是为了将功能分组在一个精细的它是为了减少单一继承的一些限制,使开发人员能够在不同类层次结构中的几个独立类中使用reuse sets of methods freely,而Abstract类只是为了提供一种模板来继承,并强制继承类实现抽象方法.

相关问题