2016-07-07 144 views
1

在PHP中测试性状的时候,我对引入特征的原因有些困惑。我做了一些小实验。首先,我直接调用的类为什么Traits不能直接实例化?

<?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

你为什么不做'$ this-> sayHello();'? – tkausl

+0

@tkausl这意味着当我在类中使用traits时,它会自动实例化。 –

+0

- “使用Traits的优点是什么?'+在不实例化的情况下调用它的方法。 – revo

回答

0

AbstractTrait类之间唯一的共同点是它不可能自己实例化a Trait/an Abstract

但他们的目的是不同的。 Trait仅用于以细粒度和一致的方式对功能进行分组。通过使开发者能够在几个独立的类中生活在不同的类层次中,Abstract类仅仅提供一种模板来继承并强制继承类实现抽象方法,从而减少单继承的一些限制。

6

Traits不应该被实例化。它们只是代码部分,您可以通过它们在您的类中重复使用它们。你可以想象,一个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

好了,所以这也许是没有办法的办法做到这一点,但我想通了如何使用特点的方式,为什么它是在某些情况下更好,为我的项目。它们是类的延伸。如果您对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框架内,以这种方式扩展日志记录类:

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包含为某些父类。只要将它与“使用”关键字放在任何应该能够将loginfo发送到数据库的类中即可。

同样的事情对我的作品与调试消息,我只写了这样的事:

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

而我调试特点是制作一个很好的格式化的警告信息:-)希望它可以帮助理解。

+0

非常感谢。这与我所需要的非常接近。 –

+0

我想你没有测试就匆忙给出了答案。你的类中的protectedHelloWorld被调用,这是抛出一个错误。它应该是公开的。也是类名称不匹配。 –

+0

你说得对。我将它们用作我的代码中的公共方法。 :-)如果你需要更多的帮助和具体的建议,就此与我联系。 – Andre

0

感谢所有发布答案的人,但我真正寻找的答案经过大量研究后得到了答案。我的问题是什么使特质不同于现有的方法,如抽象类,继承等。它在类内调用实例化的点是好的,但最大的区别是,我们可以在一个类内包含多种特性这种方式

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

另一个区别与特点VS继承的是,在特征定义的方法可以访问他们正在使用,包括私人方法和类的属性。 http://php.net/manual/en/language.oop5.traits.php#109508

另外,与接口实现不同,所有traits方法都可以在不定义它们的情况下访问。

相关问题