Using traits in PHP

10
Using traits in PHP 1. Introduction Traits are available in PHP since version 5.3. But yet so many people say when I ask about traits on the job interview: “Yes, I have heard/read about it but never used in real projects.”. Traits is a powerful tool when you know how to use it. The mission of this article is to introduce them by defining a problem they can solve and to solve it. 2. The Problem Let’s assume we are designing the 2D game called “Toy War”. Our current task is to implement all fighting units, which are for now: Tanks, Jet Fighters, Spy Airplanes and Air Defence Towers. Of cause we want to create a class for each unit. To have a good architecture we also need to define some abstractions that will help us to structurize our code. Let’s see what features all the units have. Some of them: have their position on the map can move can turn left and right can fly have a gun (can fire). Each feature provides some functionality which turns out basically as methods in our code. For example, ‘having positions’ means we can call getPosition() method and get a 2d vector, and ‘having gun’ stands for getGunDirection(), turnGun($degrees) and fire(). Let’s build a simple ‘Feature / Unit’ map to see what features each of the units do have: Feature / Unit Tank Jet Fighter Spy Airplane Air Defence Tower Has position + + + + Can move + + + -

Transcript of Using traits in PHP

Page 1: Using traits in PHP

Using traits in PHP1. IntroductionTraits are available in PHP since version 5.3. But yet so many people say when I ask about traits on the job interview: “Yes, I have heard/read about it but never used in real projects.”.Traits is a powerful tool when you know how to use it. The mission of this article is to introduce them by defining a problem they can solve and to solve it.

2. The ProblemLet’s assume we are designing the 2D game called “Toy War”. Our current task is to implement all fighting units, which are for now: Tanks, Jet Fighters, Spy Airplanes and Air Defence Towers. Of cause we want to create a class for each unit. To have a good architecture we also need to define some abstractions that will help us to structurize our code.Let’s see what features all the units have. Some of them:

● have their position on the map● can move● can turn left and right● can fly● have a gun (can fire).

Each feature provides some functionality which turns out basically as methods in our code. For example, ‘having positions’ means we can call getPosition() method and get a 2d vector, and ‘having gun’ stands for getGunDirection(), turnGun($degrees) and fire().

Let’s build a simple ‘Feature / Unit’ map to see what features each of the units do have:

Feature / Unit Tank Jet Fighter Spy Airplane Air Defence Tower

Has position + + + +

Can move forward

+ + + -

Can turn + + + -

Can fly - + + -

Has a gun + + - +

If you will look for a common features for all units you’ll see that the only one is ‘Having position’. It means that the only abstraction we can define is a Unit which just has getPosition() method.Going further we could define a MovableUnit which will provide ‘moving forward’ and ‘tuning’ features as they are applicable to the same units.

At this point we have a pretty straightforward inheritance structure:

Page 2: Using traits in PHP

But we still have two features to implement: ‘flying’ and ‘having gun’. If we forget for a moment the moving and arming functionality and draw a diagram for a flying feature we get:

Page 3: Using traits in PHP

Leaving flying and and moving behind the scene and working with arming we get:

Page 4: Using traits in PHP

But if we try to merge all these diagrams and build the inheritance structure for all features than we get:

Page 5: Using traits in PHP

This diagram says we need to inherit multiple classes for most of our units. And that is impossible in PHP.

3. The SolutionHere is what the Traits come for. The mission of a Trait is to provide some atomic functionality for an object. A Trait defines a single feature (i.e. movable or flyable) and could be applied to any class. The key feature of Traits is that you can apply any number of them to your class. It let you compose a class from different features it has and as a result -- to build more complicated but elegant architecture which will be much more adequate to the real world.With using of Traits our diagram turns to:

Page 6: Using traits in PHP

The SpyPlane, JetFighter, Tank and Tower are inherited from Unit and are using only the features they have. Which is great because it meets all the requirements and is fully implementable in PHP.Let’s see the code.

4. The Code<?php

/** * Abstract Unit class. * Implement 'has position' feature. */abstract class Unit{ protected $position;

public function getPosition() { return $this->position;

Page 7: Using traits in PHP

}}

/** * Implement 'moving' feature. */trait Movable{ public function move() { /* ... */ } public function turn($degrees) { /* ... */ }}

/** * Implement 'having gun' feature */trait Armed{ protected $gunDirection;

public function getGunDirection() { return $this->gunDirection; } public function turnGun($degrees) { /* ... */ } public function fire() { /* ... */ }}

/** * Implement 'flying' feature */trait Flyable{ public function blastOff() { /* ... */ } public function fly() { /* ... */ } public function land() { /* ... */ }}

/** * Implement the Tank which has position, can move and definitely has a gun */class Tank extends Unit{ use Movable, Armed;}

Page 8: Using traits in PHP

/** * Implement the Jet Fighter which has position, can move, fly and has a gun */class JetFighter extends Unit{ use Movable, Flyable, Armed;}

/** * Implement the Spy Plane which has position, can move and fly but is unarmed. */class SpyPlane extends Unit{ use Movable, Flyable;}

/** * Implement the Air Defence Tower which has position and gun but can't move or fly. */class Tower extends Unit{ use Armed;}

As you can see using traits is as easy as extending the abstract class. And like the methods of the ancestors the traits method could be overwritten by the descendant. But the syntax differs. For example:

/** * Implement the Tank which has position, can move and definitely has a gun */class Tank extends Unit{ use Movable; use Armed { fire as traitFire; };

Page 9: Using traits in PHP

public function fire() { /** * Do tank specific fire actions */ $this->traitFire(); }}

Here we have used as operator to give an alias for fire() method so we can implement our specific fire() using the method from the Trait.

PHP also provides the conflict resolving mechanism, ability to change visibility of methods and other useful functionality which you can learn at http://php.net/traits. Note that traits are available since PHP 5.4 which is very widespread already. So i bet you can start using it right now.

5. Wrap upTraits let us think of architectural model as of the definition of features represented as Traits and Classes which are composed from Traits in such many ways as do objects in real life. But the well-known hierarchical model is not being completely substituted with the compositional one. They complement each other giving us the ability to design graceful architectures for apps we build.

About AuthorMax Gopey is a PHP Team Leader in Ciklum who currently works on Magento projects.He has 6 year experience in developing PHP applications for the web including e-commerce and document management systems.