2

While testing for traits in PHP I was a bit confused why traits were introduced. I did some minor experiment. First I called trait methods directly in a class

<?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();

?>

I got an error

Fatal error: Cannot instantiate trait HelloWorld in C:\xampp\htdocs\test.php on line 35

But when I did this

<?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();

?>

i was able to call the trait method and the result displayed "Hello World! ". So what is advantage of using Traits and how is it different from abstract classes? Kindly help me understand the usage. Thanks.

Amit Ray
  • 3,445
  • 2
  • 19
  • 35

4 Answers4

11

Traits shoud not be instantiated. They are simply code parts, that you can reuse in your classes by useing them. You can imagine, that a trait code expands and becomes a part of your class. It is even being sad, that:

Traits are essentially language assisted copy and paste.

So your example should work like this:

<?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();
?>
Gino Pane
  • 4,740
  • 5
  • 31
  • 46
2

Thanks to all those who posted an answer but the answer which I was truly searching for I got after a lot of research. My Question was what makes Traits different from existing methods like abstract class, inheritance etc. The point that it is instantiated on calling inside a class is ok but the biggest difference is that we can include multiple traits inside a class this way

use class1, class2; 

In case of conflict when same methods exist in both the classes and we want to use methods from class2 we do this

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

Even traits can have multiple traits defined this way:

trait Class1 {
    use trait1, trait2;
}

Unlike inheritance; if a trait has static properties, each class using that trait has independent instances of those properties. Check this link http://php.net/manual/en/language.oop5.traits.php#107965

Another difference with traits vs inheritance is that methods defined in traits can access methods and properties of the class they're used in, including private ones. http://php.net/manual/en/language.oop5.traits.php#109508.

Also unlike interface implements, all the traits methods can be accessed without defining them again.

Amit Ray
  • 3,445
  • 2
  • 19
  • 35
1

Ok so this is maybe not THE way to do it but I figured a way on how to use Traits and why it is better in some cases, for my projects. They are a kind of extension for classes. If you are common with CakePHP, those Traits remind me of Behaviours for Models or Components for Controllers. Just look it up :-)

Well an abstract class is slightly different because you can use it for inheritance just like this:

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

A trait is more like an extension of a class. I am using Traits within a MVC Framework to extend classes with logging in this way:

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);

        ...
        ...
    }
}

It is very handy since I use it within every class and I do not have to write all those lines again where I have to connect to a database and generate an SQL query. And since I have a lot of inheritance through the entire MVC framework I do not have to include Logger as some parent class. Just place it with the "use"-keyword into any class that should be able to send loginfo to the database.

The same thing works for me with debug messages where I just write something like this:

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

And my Debug Trait is crafting a nicely formatted warning message :-) Hope it helps understanding.

Andre
  • 9,000
  • 5
  • 26
  • 32
  • Thanks a lot. This is very close to what I needed. – Amit Ray Jul 07 '16 at 05:46
  • I think you gave the answer in a hurry without testing. protected functions inside your class ConcreteHelloWorld is being called which is throwing an error. It should be public. Also class name does not match. – Amit Ray Jul 07 '16 at 06:13
  • You are right. I use them as public methods within my code. :-) If you need more assistance and concrete advise just contact me on this. – Andre Jul 07 '16 at 06:19
  • 1
    You said we cannot use abstract methods in traits but I tested with abstract method and it works. `sayHello(); ?>` – Amit Ray Jul 07 '16 at 06:29
  • Interesting. This didn't work for me hence I needed abstract classes. Anyway I wouldn't use it like that, even if it seems to be possbile. I will have to check why it doesn't work on my code :-(. If you want to use abstract methods in order to generate templates don't go with Traits. Use them just to expand functionality. That would be my advice. – Andre Jul 07 '16 at 06:47
0

The only common thing between an Abstract and a Trait class is that it is not possible to instantiate a Trait/an Abstract on its own.

But their purpose is different. Trait is only intended to group functionality in a fine-grained and consistent way. It is to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies where Abstract classes are just to provide a kind of template to inherit from and to force the inheriting class to implement the abstract methods.

  • In an abstract class, the methods do not have to be abstract. Therefore, it depends on the implementation of the method in the abstract class whether you have to implement it in the inheriting class or use the method directly from the abstract class. In addition, a class can inherit from only one abstract class, which has led to complex class hierarchies in the past (PHP 4 - 5). Traits, on the other hand, can be used more than one in a class. – Alexander Behling Dec 09 '21 at 10:06