I'm trying to make a class Developer
which is a subclass of Person
.
I want both of them to use the static factory pattern (or "named constructors").
I've seen some examples of that pattern, but none of them using inheritance.
Question 1
In the examples they make the constructor method always private.
Is it ok to make it protected in order to be called from the child constructor?
Or should I address the problem making the constructors always private, and trying to build the inheritance calling the parent's create
method from the child's create
method?
Question 2
When I try to instantiate either class Person or Developer, I'm getting the error below. Why?
PHP Fatal error: Declaration of Developer::create(string $name, string $surname, ?int $yearsOfExperience = NULL, ?string $preferredLanguage = NULL): Developer must be compatible with Person::create(string $name, string $surname): Person in InheritanceTest.php on line 57
It works when I delete the : self
type hints in both create
methods, but I don't understand why are they incompatibles, if Developer
is a child class of Person
.
Thanks in advance.
<?php
class Person
{
protected $name;
protected $surname;
protected function __construct(string $name, string $surname)
{
$this->name = $name;
$this->surname = $surname;
}
public static function create(string $name, string $surname): self
{
// Some validation
if($name == ''){
throw new InvalidArgumentException('A person name can not be empty.');
}
if($surname == ''){
throw new InvalidArgumentException('A person surname can not be empty.');
}
return new self($name, $surname);
}
}
class Developer extends Person
{
protected $yearsOfExperience;
protected $preferredLanguage;
protected function __construct(string $name, string $surname, ?int $yearsOfExperience, ?string $preferredLanguage)
{
parent::__construct($name, $surname);
$this->yearsOfExperience = $yearsOfExperience;
$this->preferredLanguage = $preferredLanguage;
}
public static function create(string $name, string $surname, ?int $yearsOfExperience = null, ?string $preferredLanguage = null): self
{
// Some validation
if($yearsOfExperience < 0){
throw new InvalidArgumentException('The years of experience can not be negative.');
}
if($preferredLanguage == ''){
throw new InvalidArgumentException('The preferred language can not be empty.');
}
return new self($name, $surname, $yearsOfExperience, $preferredLanguage);
}
}
Question 1:
In the examples they make the constructor method always private. Is it ok to make it protected in order to be called from the child constructor?
You have to make it protected. Otherwise child will not be allowed to call the parent's method.
Question 2:
It works when I delete the : self type hints in both create methods, but I don't understand why are they incompatibles, if Developer is a child class of Person.
Try using static
instead of self
. It might work, but I am not sure. But you will still have notice (or warning, don't remember) because factory method in Developer has different parameters than Person. In PHP this is allowed but not recommended.