Объявления условных аргументов и возвращаемых типов (также называемые подсказками типов) - PullRequest
0 голосов
/ 11 мая 2018

У меня есть следующий абстрактный класс, у которого есть аргументы и объявления типа возврата объекта Entity.Entity является вымышленным заполнителем, и в действительности они должны быть объявлены как возвращающие User (или независимо от того, какой фактический класс, который указывает EntityServices указывает).

Возможно ли использовать EntityServices useобъявления типов User вместо Entity без дублирования скрипта в классе User?Если так, то как?Если нет, существует ли обходной путь, позволяющий повторно использовать сценарий, по крайней мере, с некоторым уровнем функциональности объявления типа?

<?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

<?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

<?php
namespace NotionCommotion\Bla;
class BlaService extends \EntityService
{
    public function __construct(BlaMapper $blaMapper, \Validator $validator) {
        $this->mapper=$blaMapper;
        $this->validator=$validator;
    }
}

1 Ответ

0 голосов
/ 11 мая 2018

Вы не можете сделать это в PHP.

Как правило, разумным способом сделать это было бы просто использование наследования или интерфейсов.

Например, с наследованием:

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();
  }
}

Вы не можете изменить определение reproduce(), но вы можете вернуть потомка из исходного определения возврата.

Или с интерфейсами, что-то вроде:

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();
  }
}

Каждый методимеет свои преимущества и недостатки, поэтому вам придется посмотреть, какой из них лучше подходит для вашего случая.

...