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:
You have to make it protected. Otherwise child will not be allowed to call the parent's method.
Question 2:
Try using
static
instead ofself
. 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.