Traits + Interfaces in PHP 5.4 – The Perfect Team

PHP has been getting consistently better over the past few years. One new feature that I’m really pleased with is traits, which is similar to multiple inheritance in Java, friend classes in C++ or mixins in Ruby and Python.

Basically, traits allow your classes to share functionality without constructing any objects or inheriting from any base classes. I’ve been able to put traits to some pretty cool uses already.

One of the neatest things I’ve done is teaming them with interfaces to implement shared functionality that adheres to an interface without needing monolithic base classes. Here’s a simple example:

interface Foo
{
	public function bop();
}

trait Baz
{
	public function bop()
	{
		print 'it works!';
	}
}

class Bar implements Foo
{
	use Baz;
}

$x = new Bar();
$x->bop();

As you can see, Bar does not have a bop() method in its class definition. It’s using the definition provided by the trait. The scoping in the Baz treat still works just like you’d expect for the most part (the only trouble I’ve had so far is using parent::__construct() in a shared constructor).

Let’s look at a more complicated example (Note – this is just an excerpt from a more complicated program, it won’t work if you just copy and paste it. If you want to give traits a shot, start with the simple example and work your way up):

namespace Model\Abstraction;

interface InterfaceRead
{
	public function __construct();

	public function fetchBy($qualifiers = array());

	public function fetchAll();
}

namespace Model\Friend;

trait Read
{
	/*
	*	Fetch records using a where clause
	*/
	public function fetchBy($qualifiers = array())
	{
		$this->applyQualifiers($qualifiers);

		$result = $this->stmtPrepExecFetchAll("*");	

		return $result;
	}

	/*
	*	Fetch all records
	*/
	public function fetchAll()
	{
		return $this->fetchBy();
	}
}

namespace Model\Implementation;

class Intl extends \Model\Implementation\Base\Base implements \Model\Abstraction\InterfaceRead
{
	use \Model\Friend\Read;

	public function __construct(){
		parent::__construct();
		$this->table('country');
	}
}

Since all of my models which are read only will use the same API, it makes great sense to use traits to implement common functionality. Fortunately, if I need to, I can still override the functionality provided by the trait by simply declaring the method within my class.

Ok, so let’s take this a step further. What If I want to adhere to an interface which demands more shared functionality? Easy, just toss another trait into the mix:

namespace Model\Implementation;

class Intl extends \Model\Implementation\Base\Base implements \Model\Abstraction\InterfaceCreateRead
{
	use \Model\Friend\Create;
	use \Model\Friend\Read;

	public function __construct(){
		parent::__construct();
		$this->table('country');
	}
}

Anyway, thought this was cool and wanted to share = )

This entry was posted in PHP, Programming. Bookmark the permalink. Both comments and trackbacks are currently closed.