I have two repositories:
class RepositoryOne
{
/**
* @param int $id
* @return ModelOne
*/
public function getById($id)
{
// Search and find a ModelOne model in the db.
return new ModelOne();
}
}
class RepositoryTwo
{
/**
* @param int $id
* @return ModelTwo
*/
public function getById($id)
{
// Search and find a ModelTwo model in the db.
return new ModelTwo();
}
}
I am a skilled developer so I program to an interface. So let's refactor it to this:
interface RepositoryOneInterface
{
/**
* @param int $id
* @return ModelOne
*/
public function getById($id);
}
class RepositoryOne implements RepositoryOneInterface
{
/**
* @inheirtDoc
*/
public function getById($id)
{
// Search and find a ModelOne model in the db.
return new ModelOne();
}
}
// Same goes for ModelTwo
Turns out the logic to return a model is exactly the same. Also I have not two repositories, but seven. So I create an abstract repository interface:
interface AbstractRepositoryInterface
{
/**
* @param int $id
* @return AbstractModel
*/
public function getById($id);
}
I've also added abstract repository implementation so that it is not repeated in each repository. So the whole thing looks like this:
class AbstractModel {}
class ModelOne extends AbstractModel {}
interface AbstractRepositoryInterface
{
/**
* @param int $id
* @return AbstractModel
*/
public function getById($id);
}
interface RepositoryOneInterface extends AbstractRepositoryInterface { }
abstract class AbstractRepository implements AbstractRepositoryInterface
{
/**
* @inheirtDoc
*/
public function getById($id)
{
//$modelResource = $this->getModelResource();
// $model = $modelResource->load();
// return $model;
}
protected abstract function getModelResource();
}
class RepositoryOne extends AbstractRepository implements RepositoryOneInterface
{
protected function getModelResource()
{
// return ModelOne Resource.
}
}
Now I can reuse my abstract repository class for every repository I have (seven). The problem is that I don't have a concrete return type now (after the refactor). So if I do this:
$repositoryOne = new RepositoryOne();
$repositoryOne->getById(5);
...sure I get an instance of ModelOne; but the program sees it as an AbstractModel. If I use intellisense, I get only methods of the AbstractModel; but my repository is clearly a RepositoryOne one!
What is the right way to solve this issue so that the program perceives the return value as a ModelOne (without an explicit use of annotation on the returned variable) while maintaining the use of inheritance (not composition)