Using Traits to add more functionality to your classes in PHP
Traits are a mechanism for code reuse in single inheritance languages such as PHP.
A Trait is similar to a class, but only intended to group functionality in a fine-grained and consistent way. It is not possible to instantiate a Trait on its own. It is an addition to traditional inheritance and enables horizontal composition of behavior; that is, the application of class members without requiring inheritance. Source
Traits have been introduced in PHP 5.4.0. However, a lot of developers have not yet embraced them and taken advantage of the power that they offer.
As mentioned above in the snippet of the PHP manual, Traits are a mechanism to reuse code, making your code more DRY.
Let’s have a look at a real life example of how Traits can help you with your Phalcon project, or any project you might have.
Models
With Phalcon, we have model classes which represent pretty much a table in our database, and allows us to interact with a record or a resultset for the needs of our application.
Scenario
We have an application where we need to store information about Companies. Each Company can have one or more Customers as well as one or more Employees. We chose to store that information in three different tables.
For each Employee or Customer, we need to store their first name, middle name and last name. However, we also need to be able to show the full name in this format:
<Last name>, <First Name> <Middle Name>
Using custom getter
In each model we can use a custom getter method in the Phalcon model to calculate the full name of the record.
Employee
namespace NDN\Models;
class Employee
{
...
public function getFullName()
{
return trim(
sprintf(
'%s, %s %s',
$this->getLastName(),
$this->getFirstName(),
$this->getMiddleName()
)
);
}
}
Customer
namespace NDN\Models;
class Customer
{
...
public function getFullName()
{
return trim(
sprintf(
'%s, %s %s',
$this->getLastName(),
$this->getFirstName(),
$this->getMiddleName()
)
);
}
}
The above introduces a problem. If we want to change the behavior of the getFullName
we will have to visit both models and make changes to the relevant methods in each model. In addition, we are using the same code in two different files i.e. duplicating code and effort.
We could create a base model class that our Customer
and Employee
models extend and put the getFullName
function in there. However that increases the class extensions and could lead to maintenance nightmares.
For instance we will have to create the base model class that only Customer
and Employee
models extend but what would happen if we need common functionality for other models? We will need to then create another base model class and so on and so forth. If we end up piling all the common functionality into one base model class then we will end up with functions that would not apply to all of our models and thus a maintenance nightmare.
NOTE: We can also use the afterFetch
method to create a calculated field which will be available for us to use. We can use either the getter or the afterFetch
like so:
namespace NDN\Models;
class Customer
{
...
public function afterFetch()
{
$this->full_name = trim(
sprintf(
'%s, %s %s',
$this->getLastName(),
$this->getFirstName(),
$this->getMiddleName()
)
);
}
}
Traits
We can use a trait to offer the same functionality, keeping our code DRY. Since a Trait is not a class that can be instantiated by itself, we attach it to wherever we need to, in this case the Employee
and Customer
models.
namespace NDN\Traits;
trait FullNameTrait
{
/**
* Gets the user first/last/med name and formats it in a readable format
*
* @return string
*/
public function getFullName()
{
return trim(
sprintf(
'%s, %s %s',
$this->getLastName(),
$this->getFirstName(),
$this->getMiddleName()
)
);
}
}
We can attach now this trait to the relevant models
Employee
namespace NDN\Models;
use NDN\Traits\FullNameTrait;
class Employee
{
use FullNameTrait;
}
Customer
namespace NDN\Models;
use NDN\Traits\FullNameTrait;
class Customer
{
use FullNameTrait;
}
Now we can use the getFullName()
function in our two models to get the full name of the Employee or Customer calculated by the relevant model fields.
// Customer:
// first_name: John
// middle_name: Mark
// last_name: Doe
// Prints: Doe, John Mark
echo $customer->getFullName();
// Employee:
// first_name: Stanley
// middle_name: Martin
// last_name: Lieber
// Prints: Lieber, Stanley Martin
echo $employee->getFullName();
Conclusion
Traits can be very powerful and helpful allies, keeping our code very flexible and reusable.
Give it a try!
-
Nikolaos Dimopoulos
Boldly goes where no other coder has gone before.... and other ramblings
Recent Posts
-
Setting up Docker for Qubes OS
2024-10-05 -
PhpStorm cannot create scratch files
2023-12-07 -
PHP 8.2 Deprecation of Dynamic Properties
2023-07-18 -
New Look
2023-06-12 -
Linux Swap file in RAM
2023-04-17
Tag Cloud
-
amazon (3)
android (1)
angularjs (7)
apps (1)
aurora (1)
aws (1)
backup (2)
bash (1)
bitbucket (1)
blog (2)
books (1)
bootstrap (1)
buzz (1)
cPanel (1)
cache (1)
celebrations (4)
chromium (3)
chromium os (3)
cloud computing (3)
codacy (1)
codecov (1)
communications (1)
composer (1)
conversion (1)
copy (1)
degoogle (5)
design (1)
design patterns (3)
discord (1)
docker (1)
docs (3)
documentation (1)
ec2 (3)
emerge (1)
encoding (1)
factory (1)
froyo (1)
fujitsu (1)
gentoo (7)
git (3)
github (2)
gmail (3)
google (16)
google apps (4)
google maps (1)
gource (1)
ha (1)
hosting (2)
how to (36)
igbinary (1)
information (5)
input (1)
installation (6)
internet (1)
iphone (1)
json (2)
libreoffice (1)
linux (13)
localization (1)
lts (1)
mariadb (1)
memorial day (1)
metrics (1)
migration (1)
mod_rewrite (1)
mov (1)
mp4 (1)
mysql (6)
nas (1)
netlify (1)
new look (1)
nexus one (2)
nfs (1)
notebook (1)
online storage (1)
openoffice (1)
opinion (1)
oracle (1)
patterns (1)
payroll (1)
performance (3)
personal (9)
phalcon (12)
php (23)
php8 (2)
php82 (1)
phpstorm (1)
phpunit (2)
picasa (2)
portage (1)
privacy (1)
programming (9)
proxy (1)
qubes os (1)
rant (5)
rdbms (1)
rds (1)
relationships (1)
release (1)
remove (1)
replication (1)
review (9)
rsync (2)
s1300 (1)
scan (1)
scratch (1)
serialize (1)
series (9)
singleton (1)
sorting (1)
spaceship (1)
spam (1)
ssl (1)
static (1)
storage (6)
submodules (1)
subversion (2)
svn (1)
swap (1)
tdd (1)
technorati (1)
test driven development (1)
testability (1)
testing (2)
titles (1)
traits (1)
ua (1)
ubuntu (1)
update (6)
upgrade (1)
usa (2)
usort (1)
utf8 (1)
video (1)
visualization (1)
vps (1)
webm (1)
website (1)
wget (1)
zend framework (4)
zram (1)
zstd (1)