Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typesafe / Type hinting in child classes of an abstract class in PHP

I'm setting up a new section of a framework I've inherited. It's a chance to really enforce some best practice, so I'm trying to do as much as possible.

The framework is running in php5.4 (windows environment).

I've set up an abstract class, BaseModel. In this I define several core bits of functionality, for example: common accessors and common db interaction.

I then extend this to create the models I'll be using. In the test case the file "UserModel" creates a class called "User" .

In BaseModel I'm creating the following abstract function:

abstract public function getById($id);

Within the UserModel I then define this function

public function getById($id)
{
    // just a test!
    return 'this works!';
}

I would like to enforce typesafeing. However I get errors if I do anything like this:

public function getById(User $id)
{
    // just a test!
    return 'this works!';
}

I can do the following

abstract public function getById(BaseModel $id);

public function getById(BaseModel $id)
{
    // just a test!
    return 'this works!';
}

Which works, but is also a bit less useful to be honest. A User is of type BaseModel, but so would every other extended class be. What I want to do is this:

abstract public function getById(BaseModel $id);

public function persist(User $item)
{
    // just a test!
    return 'this works!';
}

I know I can add in a line doing manual typesafing, along these lines (pseudocode)

if ($item instanceof User)
{
//do stuff
}

However - this seems to be a bit of a work around, as opposed to finding the true approach.

I have a sinking feeling that this kind of "smart/aware class" feature isn't available in php.

Can anyone confirm/deny this or provide a more elegant work around?

like image 367
elb98rm Avatar asked Dec 04 '13 11:12

elb98rm


1 Answers

Having done a bit more digging around, and thanks to a helpful post from deceze, I think this idea hasn't been implemented. He has pointed out a similar answer it to which breaks the rules of SOLID.

http://en.wikipedia.org/wiki/SOLID

Basically - This says that I cannot change the parent class: this is the point of "extend". I can only extend, not modify the parent class. Changing the typesafeing is modifying the class.

HOWEVER - I would argue that this example doesn't break the rules of SOLID. Typesafing with class that is extended from the base class should be allowed: You can never have a "User" that is not a "BaseModel"... so it is not modifying the parent class.

It looks like the only way to truly do this is

if ($item instanceof User) 
{
// logic
}

In my case the parent class is probably enough to catch most issues, but it's a shame I can't typesafe it the way I intended.

[Thanks to deceze. Upvoted.]

like image 115
elb98rm Avatar answered Sep 25 '22 13:09

elb98rm