Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 条件参数和返回类型声明(又称类型暗示)_Php_Oop_Type Hinting - Fatal编程技术网

Php 条件参数和返回类型声明(又称类型暗示)

Php 条件参数和返回类型声明(又称类型暗示),php,oop,type-hinting,Php,Oop,Type Hinting,我有以下抽象类,它具有实体对象的参数和返回类型声明Entity是一个虚构的占位符,实际上它们应该声明为显示返回的User(或者扩展EntityServices的实际类指定的任何内容) 是否可以让EntityServices使用User的类型声明,而不是Entity,而不复制User类中的脚本?如果是,怎么做?如果没有,是否有一种变通方法允许脚本至少在某种级别的类型声明功能下重用 <?php namespace NotionCommotion; abstract class EntitySe

我有以下抽象类,它具有
实体
对象的参数和返回类型声明
Entity
是一个虚构的占位符,实际上它们应该声明为显示返回的
User
(或者扩展
EntityServices
的实际类指定的任何内容)

是否可以让
EntityServices
使用
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();
}
BlaServices
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;
    }
}
<?php
namespace NotionCommotion\Bla;
class BlaService extends \EntityService
{
    public function __construct(BlaMapper $blaMapper, \Validator $validator) {
        $this->mapper=$blaMapper;
        $this->validator=$validator;
    }
}

在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();
  }
}
您不能更改
repearch()
定义,但可以从原始返回定义返回子体

或者使用接口,例如:

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

每种方法都有其优缺点,因此您需要看看哪种方法对您的案例更有意义。

这可能吗
?什么是可能的?不清楚您想要什么。我将编辑原始范围以更好地描述。谢谢你在说什么?@GabrielHeming我不这么认为。我希望使扩展父抽象类中的方法更窄,并与扩展子类中的方法相匹配。实际上,接口解决方案似乎不适用。它与
string
一起工作,因为所有类中的方法都是这样声明的。我希望可以在父类中禁用声明,而只在接口中包含声明,但是,这会导致错误。@user1032531如果类实现了接口,则需要完全实现它。如果您不想被限制为返回类型,只需在接口声明中省略它。是的,我刚刚阅读了文档:
实现接口的类必须使用与接口中定义的方法签名完全相同的方法签名。不这样做将导致致命错误。
我可以在接口中省略它们,但这样会失去接口的一些好处。由于其他人不认为这是一个问题,我想我并不真正理解如何使用它们。不过,这是实现你想要的唯一方法。其余部分是关于正确设计应用程序的。:)