Web lists-archives.com

Re: [PHP] How do I handle covariant parameters and not fall foul of LSP.




I think LSP becomes an issue in situations where you want to swap
implementations. Since I can't really think of such a use case when using
repositories, you can even name your methods more specifically.

abstract class BaseRepo
{
    protected function processEntity(BaseEntity $anEntity)
    {
        ...
    }
}

class PersonRepo extends BaseRepo
{
    public function processPerson(PersonEntity $aPerson)
    {
        $this->processEntity($aPerson);
    }
}

class CatRepo extends BaseRepo
{
    public function processCat(CatEntity $aCat)
    {
        $this->processEntity($aCat);
    }
}

If the process method is doing storage related things I don't think is a
good idea to move it to the Entity hierarchy. The main idea of repositories
is to provide a collection like interface to storage, the other idea common
to persistence related patterns is to free entities from persistence
responsibilities and make them more focused on the domain logic.



On Mon, Feb 13, 2017 at 8:55 PM, David Harkness <david.h@xxxxxxxxxxxxxxxxx>
wrote:

> The problem with LSP is that every BaseRepo must be able to be substituted
> for any other, but each concrete form only handles its own concrete entity
> type. The contract of processEntity(BaseEntity) is "I will process any
> concrete BaseEntity subclass", but PersonRepo violates this contract by
> declaring that it will only process PersonEntity.
>
> Java uses Generics to solve this, but you'll have to fake it with
> instanceof for safety. Note that you're *still* violating LSP here, but you
> can't really avoid it given what you want to do.
>
>     class PersonRepo extends BaseRepo
>     {
>         public function processEntity(BaseEntity $entity)
>         {
>             parent::processEntity($entity);
>             if (!($entity instanceof Person) {
>                 throw new RepoException('Must be a Person');
>             }
>             ...
>         }
>     }
>
> Well, you could invert the responsibility to save LSP by moving the
> concrete functionality into the entity, but it will probably be a little
> hacky.
>
>     abstract class BaseEntity {
>         public abstract function process();
>     }
>
>     class PersonRepo extends BaseRepo
>     {
>         public function processEntity(BaseEntity $entity)
>         {
>             parent::processEntity($entity);
>             $entity->process();
>             ...
>         }
>     }
>
> Cheers!
> David
>