Reputation: 26331
I have the following abstract class which has argument and return type declarations of the Entity
object. Entity
is a fictional placeholder, and in reality they should be declared to show returning User
(or whatever the actual class which extends EntityServices
specifies).
Is it possible to have EntityServices
utilize type declarations of User
instead of Entity
without duplicating the script in the User
class? If so, how? If not, is there a workaround that will allow the script to be reused with at least some level of type declaration functionality?
<?php
namespace NotionCommotion;
abstract class EntityService
{
//Constructor in child
public function get(int $id): ?Entity {
//Will return User or Bla argument based on the extending class
return $this->mapper->read($id);
}
public function create(array $data): Entity {
//Will return User or Bla argument based on the extending class
if (!$this->validator->load($this->getValidationFile())->isValid($data)) throw new UserValidationError($this->validator, $data);
$this->doTransation(function(){$this->mapper->add($data);});
}
public function update(array $data, int $id): Entity {
//Will return User or Bla argument based on the extending class
if (!$this->validator->load($this->getValidationFile())->nameValueisValid($data)) throw new UserValidationError($this->validator, $data);
$this->doTransation(function(){$this->mapper->update($data);});
}
public function delete(int $id): void {
$this->mapper->delete($id);
}
public function whatever(Entity $whatever) {
//Requires User or Bla argument based on the extending class
}
protected function doTransation($f){
try {
$f();
$this->pdo->commit();
} catch (\PDOException $e) {
$this->pdo->rollBack();
throw($e);
}
}
abstract protected function getValidationFile();
}
UserServices
class
<?php
namespace NotionCommotion\User;
class UserService extends \EntityService
{
public function __construct(UserMapper $userMapper, \Validator $validator, Foo $foo) {
$this->mapper=$userMapper;
$this->validator=$validator;
$this->foo=$foo;
}
}
BlaServices
class
<?php
namespace NotionCommotion\Bla;
class BlaService extends \EntityService
{
public function __construct(BlaMapper $blaMapper, \Validator $validator) {
$this->mapper=$blaMapper;
$this->validator=$validator;
}
}
Upvotes: 1
Views: 276
Reputation: 47646
You can't do this in PHP.
Generally, a sane way of doing it would be just using inheritance or interfaces.
E.g, with inheritance:
class Animal {}
class Cat extends Animal {}
class Service {
public function reproduce() : Animal {
return new Animal();
}
}
class ImprovedService extends Service {
public function reproduce() : Animal {
return new Cat();
}
}
You can't change reproduce()
definition, but you can return a descendant from the original return definition.
Or with interfaces, something like:
interface Mammal {
public function makeSound() : string;
}
class Dog implements Mammal {
public function makeSound() : string {
return "Bark!";
}
}
class GenericMammal implements Mammal {
public function makeSound() : string {
return "???";
}
}
class Service {
public function test() : Mammal {
return new GenericMammal();
}
}
class ImprovedService extends Service {
public function test() : Mammal {
return new Dog();
}
}
Each method has advantages and disadvantages, so it would fall upon you to see which one makes better sense for your case.
Upvotes: 1