Na navigaci | Klávesové zkratky

How to Handle Getters When They Have Nothing to Return?

Software development often presents dilemmas, such as how to handle situations when a getter has nothing to return. In this article, we'll explore three strategies for implementing getters in PHP, which affect the structure and readability of code, each with its own specific advantages and disadvantages. Let's take a closer look.

Universal Getter with a Parameter

The first solution, used in Nette, is to create a single getter method that can either return null or throw an exception if the value is not available, depending on a boolean parameter. Here is an example of what the method might look like:

public function getFoo(bool $need = true): ?Foo
{
    if (!$this->foo && $need) {
        throw new Exception("Foo not available");
    }
    return $this->foo;
}

The main advantage of this approach is that it eliminates the need to have several versions of the getter for different use cases. A former disadvantage was the poor readability of user code using boolean parameters, but this has been resolved with the introduction of named parameters, allowing you to write getFoo(need: false).

However, this approach may cause complications in static analysis, as the signature implies that getFoo() can return null under any circumstances. Tools like PHPStan allow explicit documentation of method behavior through special annotations, improving code understanding and its correct analysis:

/** @return ($need is true ? Foo : ?Foo) */
public function getFoo(bool $need = true): ?Foo
{
}

This annotation clearly defines what return types the method getFoo() can generate depending on the value of the parameter $need. However, for instance, PhpStorm does not understand it.

Pair of Methods: hasFoo() and getFoo()

Another option is to divide the responsibility into two methods: hasFoo() to verify the existence of the value and getFoo() to retrieve it. This approach enhances code clarity and is intuitively understandable.

public function hasFoo(): bool
{
    return (bool) $this->foo;
}

public function getFoo(): Foo
{
    return $this->foo ?? throw new Exception("Foo not available");
}

The main problem is redundancy, especially in cases where the availability check itself is a complex process. If hasFoo() performs complex operations to verify if the value is available, and then this value is retrieved again using getFoo(), these operations are repeated. Hypothetically, the state of the object or data might change between the calls to hasFoo() and getFoo(), leading to inconsistencies. From a user's perspective, this approach may be less convenient as it forces calling a pair of methods with repeating parameters. It also prevents the use of the null-coalescing operator.

The advantage is that some static analysis tools allow defining a rule that after a successful call to hasFoo(), no exception will be thrown in getFoo().

Methods getFoo() and getFooOrNull()

The third strategy is to split the functionality into two methods: getFoo() to throw an exception if the value does not exist, and getFooOrNull() to return null. This approach minimizes redundancy and simplifies logic.

public function getFoo(): Foo
{
    return $this->getFooOrNull() ?? throw new Exception("Foo not available");
}

public function getFooOrNull(): ?Foo
{
    return $this->foo;
}

An alternative could be a pair getFoo() and getFooIfExists(), but in this case, it might not be entirely intuitive to understand which method throws an exception and which returns null. A slightly more concise pair would be getFooOrThrow() and getFoo(). Another possibility is getFoo() and tryGetFoo().

Each of these approaches to implementing getters in PHP has its place depending on the specific needs of the project and the preferences of the development team. When choosing a suitable strategy, it's important to consider the impact on readability, maintenance, and performance of the application. The choice should reflect an effort to make the code as understandable and efficient as possible.

6 months ago in section PHP | blog written by David Grudl | back to top

You might be interested in

Leave a comment

Text of the comment
Contact

(kvůli gravataru)



*kurzíva* **tučné** "odkaz":http://example.com /--php phpkod(); \--

phpFashion © 2004, 2024 David Grudl | o blogu

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.