Scot Calvin
Scot Calvin

Reputation: 292

How to avoid duplicating implemented getter function in PHP

While this question is about methods of solving this problem, I am particularly interested in good clean OO design and solutions that conform to current PHP best practices. Thanks in advance for taking a look.

I have the following interface:

<?php

interface Tool {

  /**
   * Return the unique name of the tool
   */
  public function getName();

}

The majority of classes that implement this interface in my project looks like this:

<?php

class Drill implements Tool {

    protected $toolName = 'drill';

    public function getName() {
        return $this->toolName;
    }

}

And so the problem is I have dozens of classes that repeat this logic, duplicating the $toolName property and getName() logic, breaking the simple rule of 'Don't repeat yourself'

One solution I have considered is the following:

<?php

abstract class BaseTool implements Tool {

    public function getName() {
        return $this->toolName;
    }

}

Then simply have tool classes extend the abstract BaseTool class:

<?php

class Drill extends BaseTool {

    protected $toolName = 'drill';
}

However this now means that I lose the ability to force implementing classes to define the function getName() if they extend the BaseTool class, which can lead to incorrect implementations.

I also think that by having the BaseTool class return $this->toolName, it is making assumptions about the implementing classes and breaks encapsulation.

I have used a simple example to demonstrate the problem but hope you get what I'm trying to solve, and that this problem may also relate to more complex situations. Appreciate your thoughts.

Upvotes: 2

Views: 94

Answers (3)

Fuhrmanator
Fuhrmanator

Reputation: 12922

How to avoid duplicating implemented getter function in PHP

Abstract classes are often used to group duplicated code. You're on the right path. As for your doubts about the choice...

However this now means that I lose the ability to force implementing classes to define the function getName() if they extend the BaseTool class, which can lead to incorrect implementations.

By extending the BaseTool class, a class inherits getName() (that's the idea with defining it in the abstract class). I'm not sure why that leads to incorrect implementations or why you'd have to "force implementing classes to define it." They get it automatically by extending the abstract class.

I also think that by having the BaseTool class return $this->toolName, it is making assumptions about the implementing classes and breaks encapsulation.

It might be cleaner if you define the toolName in the abstract class, and you set its value in the constructor?

<?php

abstract class BaseTool implements Tool {

    protected $toolName;

    public function __construct($toolName)
    {
        $this->toolName = $toolName;
    }

    public function getName() {
        return $this->toolName;
    }

}

You define a constructor in the extended class to put its name:

<?php

class Drill extends BaseTool {

    public function __construct()
    {
        parent::__construct("drill");
    }

}

Upvotes: 0

Ankh
Ankh

Reputation: 5728

If you're using PHP 5.4.0+, check out traits!

You could create a ToolInterfaceTrait that just contains the getters / setters for the variable $toolName

Upvotes: 3

hek2mgl
hek2mgl

Reputation: 158160

Your attempt looks good. Nothing more to say.

However this now means that I lose the ability to force implementing classes to define the function getName() if they extend the BaseTool class, which can lead to incorrect implementations.

You still force them, they need to inherit a class which implements them or implement them on their own.

If it is not feasible that all classes which should implement Tool extend from BaseTool, feel free to create more base classes which implement getName() or implement it directly, like you wish.

Btw, if you plan that all tools should extend BaseTool, then the interface isn't necessary at all, at least not for this use case. Interfaces are used for situations where not all classes which are expeted to implement it are inherited from the same base class.

Upvotes: 1

Related Questions