kind


1. Use less inheritance and more use of composition

2. Avoid coherent interfaces

##3. It is recommended to use final classes

1. Use less inheritance and more use of composition

As mentioned before in Design Patterns by the Gang of Four Say, we should try to give priority to composition rather than inheritance. There are many benefits to using both inheritance and composition. The main point of this guideline is that when you instinctively use inheritance, try to think about whether composition might better model your needs. In some cases, this is true.

The next thing you may be thinking is, "So when should I use inheritance?" The answer depends on your question, but here are some instructions for when inheritance is better than composition:

Your inheritance expresses the relationship of "is one" rather than "has one" (human->animal, user->user details)

You can reuse the code of the base class (humans can be like animals Move)

You want to make global changes to all derived classes by modifying the base class (modify the energy consumption of animals when they move)

Bad:

 class Employee
{
    private $name;
    private $email;
 
    public function __construct(string $name, string $email)
    {
        $this->name = $name;
        $this->email = $email;
    }
 
    // ...
}
 
 
// 不好,因为 Employees "有" taxdata
// 而 EmployeeTaxData 不是 Employee 类型的
 
 
class EmployeeTaxData extends Employee
{
    private $ssn;
    private $salary;
    
    public function __construct(string $name, string $email, string $ssn, string $salary)
    {
        parent::__construct($name, $email);
 
        $this->ssn = $ssn;
        $this->salary = $salary;
    }
 
    // ...
}

Good:

class EmployeeTaxData
{
    private $ssn;
    private $salary;
 
    public function __construct(string $ssn, string $salary)
    {
        $this->ssn = $ssn;
        $this->salary = $salary;
    }
 
    // ...
}
 
class Employee
{
    private $name;
    private $email;
    private $taxData;
 
    public function __construct(string $name, string $email)
    {
        $this->name = $name;
        $this->email = $email;
    }
 
    public function setTaxData(string $ssn, string $salary)
    {
        $this->taxData = new EmployeeTaxData($ssn, $salary);
    }
 
    // ...
}

2. Avoid coherent interface

Continuous interface

Fluent interface is a An API design pattern designed to improve code readability in object-oriented programming. It is based on method chainingMethod chaining

Where there is context, code complexity can be reduced, such as PHPUnit Mock Builder and Doctrine Query Builder , more situations will bring greater costs:

While there can be some contexts, frequently builder objects, where this pattern reduces the verbosity of the code (for example the PHPUnit Mock Builder or the Doctrine Query Builder), more often it comes at some costs:

1. Breaks object encapsulation

2. Breaks decorator pattern

3. Not working in test components Easy to do

mock

4.

diff that leads to submission is not easy to read

5. To learn more please read Why Coherent Interfaces Are Bad, author Marco Pivetta.

Bad:

class Car
{
    private $make = 'Honda';
    private $model = 'Accord';
    private $color = 'white';
 
    public function setMake(string $make): self
    {
        $this->make = $make;
 
        // NOTE: Returning this for chaining
        return $this;
    }
 
    public function setModel(string $model): self
    {
        $this->model = $model;
 
        // NOTE: Returning this for chaining
        return $this;
    }
 
    public function setColor(string $color): self
    {
        $this->color = $color;
 
        // NOTE: Returning this for chaining
        return $this;
    }
 
    public function dump(): void
    {
        var_dump($this->make, $this->model, $this->color);
    }
}
 
$car = (new Car())
  ->setColor('pink')
  ->setMake('Ford')
  ->setModel('F-150')
  ->dump();

Good:

 class Car
{
    private $make = 'Honda';
    private $model = 'Accord';
    private $color = 'white';
 
    public function setMake(string $make): void
    {
        $this->make = $make;
    }
 
    public function setModel(string $model): void
    {
        $this->model = $model;
    }
 
    public function setColor(string $color): void
    {
        $this->color = $color;
    }
 
    public function dump(): void
    {
        var_dump($this->make, $this->model, $this->color);
    }
}
 
$car = new Car();
$car->setColor('pink');
$car->setMake('Ford');
$car->setModel('F-150');
$car->dump();

3. It is recommended to use final Class

Try to use

final keywords when possible:

1. Prevent uncontrolled inheritance chains

2. Encourage combination.

3. Encourage the single responsibility model.

4. Encourage developers to use your public methods instead of obtaining access to protected methods through inherited classes.

5. It is possible to modify the code without breaking the application that uses your class.

The only condition is that your class should implement an interface and no other public methods are defined.

For more informations you can read the blog post on this topic written by Marco Pivetta (Ocramius).

bad:

final class Car
{
    private $color;
    
    public function __construct($color)
    {
        $this->color = $color;
    }
    
    /**
     * @return string The color of the vehicle
     */
    public function getColor()
    {
        return $this->color;
    }
}

good:

 interface Vehicle
{
    /**
     * @return string The color of the vehicle
     */
    public function getColor();
}
 
final class Car implements Vehicle
{
    private $color;
    
    public function __construct($color)
    {
        $this->color = $color;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getColor()
    {
        return $this->color;
    }
}