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 ๐ค
Top 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 ๐
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.
One more way: use Closure::bind().
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 ๐
Good call ๐ I'm adding it!
Interesting.
Thanks for posting. Where are exactly the points that only can do within >= 8.x versions?