DEV Community

Benjamin Delespierre
Benjamin Delespierre

Posted on β€’ Edited on

43 7

All flavors of PHP 8 getters

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";
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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";
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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";
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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;
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… Pros

  • Same as above
  • Less code to write if you also need a setter

❌ Cons

Magic getter

/**
 * @property string $name
 */
class User
{
    private string $name = "Robert PAULSON";

    public function __get($key)
    {
        if ($key == 'name') {
            return $this->name;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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';
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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';
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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"
Enter fullscreen mode Exit fullscreen mode

βœ… 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
Enter fullscreen mode Exit fullscreen mode

βœ… 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"
Enter fullscreen mode Exit fullscreen mode

βœ… 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 πŸ€—

Sentry image

See why 4M developers consider Sentry, β€œnot bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (10)

Collapse
 
doekenorg profile image
Doeke Norg β€’

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!

Collapse
 
bdelespierre profile image
Benjamin Delespierre β€’

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 πŸ˜…

Collapse
 
andreidascalu profile image
Andrei Dascalu β€’

You have a weird definition of what's a pro and a con:

  • 2 birds with one stone => violate SRP, which you mention so technically you're calling the pro also a con (fair, but confusing)
  • can execute arbitrary code => violate the meaning of getter (eg: return the underlying value, the expectation is not to have arbitrary side-effects), technically is a call to violate SRP

"Getter/setter" - also same 'con' as public access: anyone can change the value.

Collapse
 
bdelespierre profile image
Benjamin Delespierre β€’

Thanks for your message. Your concerns actually make sense. I'll change the article.

Collapse
 
kastaneda profile image
ΠšΠ°Ρ€Π»ΠΎΡ ΠšΠ°ΡΡ‚Π°Π½Π΅Π΄Π° ✳️ β€’

One more way: use Closure::bind().

Collapse
 
doekenorg profile image
Doeke Norg β€’ β€’ Edited
class SomeClass
{
    private string $title = 'Some Class Title';
}

$some = new SomeClass();

$closure = function() {
    return $this->title;
};

$get_title = $closure->bindTo($some, $some);

echo $get_title(); // Some Class Title
Enter fullscreen mode Exit fullscreen mode

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 into CacheItem DTO's.

Collapse
 
bdelespierre profile image
Benjamin Delespierre β€’

Interesting way of breaking encapsulation πŸ‘

Collapse
 
bdelespierre profile image
Benjamin Delespierre β€’

Good call πŸ˜‰ I'm adding it!

Collapse
 
sujitagarwal profile image
Sujit Agarwal β€’

Interesting.

Collapse
 
vuong profile image
Vuong β€’

Thanks for posting. Where are exactly the points that only can do within >= 8.x versions?

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

πŸ‘‹ Kindness is contagious

Please leave a ❀️ or a friendly comment on this post if you found it helpful!

Okay