All flavors of PHP 8 getters
Benjamin Delespierre
Posted on August 1, 2021
Getters are the most basic methods a class can have. Their only job is to return a value, usualy from its properties. There's isn't much to say about it.
Or is there? ๐คจ
Today I'm going to present you 10 ways you can implement a getter in PHP 8.0.
- Public access
- Classic getter
- Classic getter, but without a verb
- Getter/setter
- Magic getter
- Offset getter
- Magic call
- Reference getter
- Encapsulation violation ๐คซ
- Returning a closure
Let's get started!
Public access
class User
{
public string $name = "Robert PAULSON";
}
โ Pros
- No need to write a getter method
โ Cons
- Cannot be part of an interface
- Exposes object's internal state
Classic getter
class User
{
public function getName(): string
{
return "Robert PAULSON";
}
}
โ Pros
- Can be part of an interface
- Straightforward and easy to understand
โ Cons
- ยฏ\_(ใ)_/ยฏ
Classic getter, but without a verb
class User
{
public function name(): string
{
return "Robert PAULSON";
}
}
โ Pros
- Can still be part of an interface
- Shorter than getName
โ Cons
- Methods without a verb can be confusing
Getter/setter
class User
{
private string $name = "Robert PAULSON";
public function name(?string $name = null): string
{
if ($name) {
$this->name = $name;
}
return $this->name;
}
}
โ Pros
- Same as above
- Less code to write if you also need a setter
โ Cons
- What if you want to set the value to
null
? - Violates the Single Responsibility Principle
Magic getter
/**
* @property string $name
*/
class User
{
private string $name = "Robert PAULSON";
public function __get($key)
{
if ($key == 'name') {
return $this->name;
}
}
}
โ Pros
- You can expose protected and private members on your own terms
โ Cons
- You can't always typehint the returned value
- Some companies have banned this (seriously)
- You're going to need an annotation
@property
or PHPStorm won't "see" it
Offset getter
class User extends ArrayAccess
{
public offsetExists($offset): bool
{
return $offset == 'name';
}
public offsetGet($offset)
{
if ($offset == 'name') {
return 'Robert PAULSON';
}
}
}
โ Pros
- Same as magic getter
- Super cool
$object['name']
notation
โ Cons
- Same as magic getter
Magic call
/**
* @method string getName()
*/
class User
{
public function __call($method, $args)
{
if ($method == 'getName') {
return 'Robert PAULSON';
}
}
}
โ Pros
- Same as using magic getters
- Save "space" by grouping several getters in one method
- You can create aliases for your existing getters without adding new methods
โ Cons
- You're going to need an annotation
@method
or PHPStorm won't "see" it - If you need this to lower the number of methods in your class, it might be the sign of a design issue
Reference getter
class User
{
private string $name = "Robert PAULSON";
public function &getName(): string
{
return $this->name;
}
}
// usage
$user = new User;
var_dump($user); // string(14) "Robert PAULSON"
$name = &$user->getName();
$name = "Tyler DURDEN";
var_dump($user); // string(12) "Tyler DURDEN"
โ Pros
- Used for performance optimizations (eliminates the function call overhead)
โ Cons
- I hope you know what you're doing
Encapsulation violation
class User
{
private string $name = "Robert PAULSON";
}
// can't access $name because it's private
// and there's no getter to obtain its value
$user = new User();
// let's use the reflection API
$property = (new ReflectionClass(User::class))->getProperty('name');
$property->setAccessible(true);
$name = $property->getValue($user);
echo $name; // Robert PAULSON
โ Pros
- Very useful for debugging classes you don't own without rewriting them
โ Cons
- Very slow
- Quite ugly
Returning a closure
class User
{
private $name = "Robert PAULSON";
public function obtainNameGetter(): callable
{
return fn() => $this->name;
}
public function setName(string $name): void
{
$this->name = $name;
}
}
// usage
$user = new User();
$getter = $user->obtainNameGetter();
echo $getter(); // "Robert PAULSON"
// now let's change the username
$user->setName("Tyler DURDEN");
echo $getter(); // "Tyler DURDEN"
โ Pros
- Can be used to solve circular dependencies
- Poor-man lazy-loading implementation
- You can compose the returned closure
โ Cons
- The returned closure is a black-box
- You cannot serialize the returned value easily
Did I miss something? Tell me what you think of this list in the comments and don't forget to like/follow, it keeps me motivated to write more articles for you ๐ค
๐ ๐ช ๐
๐ฉ
Benjamin Delespierre
Posted on August 1, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.