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 ๐ค
Oldest comments (10)
I know the list is about 8.0, but in PHP 8.1 you can add
readonly
to the public parameter to prevent this con:Anyone can change the value
. Nice list though!Thanks, I'll add it as soon as PHP 8.1 comes out. There won't be much need for 99% of getters after that release ๐
One more way: use Closure::bind().
Good call ๐ I'm adding it!
I think this is the idea. Very nasty, but indeed effective :-)
::bind()
is the static variant of->bindTo()
For those that want an example from the wild, checkout this NullAdapter from Symfony. It uses
Closure::bind()
to wrap items from the cache intoCacheItem
DTO's.Interesting way of breaking encapsulation ๐
Interesting.
You have a weird definition of what's a pro and a con:
"Getter/setter" - also same 'con' as public access: anyone can change the value.
Thanks for your message. Your concerns actually make sense. I'll change the article.
Thanks for posting. Where are exactly the points that only can do within >= 8.x versions?