Late Static Binding
PHP's Late Static Binding is a pretty awesome concept when you get your head around it. In effect it allows you to code an object to handle the data contained within a child (extending) class. You can then change out the child class and as a result the parent (base) class will do something differently.
In short, late static binding is an inheritance-aware self
call. [My quote, feel free to use it elsewhere]
The 'Model'
Just a quick recap. The model is a layer. It is the layer in MVC. Anyone who tells you that they have a "user model", or a "Post Model" does not know what they are talking about.
Feel free to re-cap on how should a model be structured in MVC and start referring to these (what should be) "dumb objects" as Entities. You have a User
entity and a Post
entity.
Extending
When you extend an object, you are saying ExtendingObject
is-a ParentObject
. By extending User
from Model
, you are saying that the User
is-a Model
, which we have already established by definition is invalid. You are better having a generic DB
object and passing that in via Dependency Injection.
Constructors
Your constructors should have no business logic. When you create an object you are creating it in a specific state. This can be enforced by constructor parameters, typehints and exceptions for invalid scalar parameters. Once the object is created, then you run a method on it like getSchema()
.
So, to re-cap:
- A
User
is-not-a Model
- The model is a layer, not an object
- Pass in other objects via dependency injection and adhere to SRP
- Your constructors should have no business logic
LSB for aphillips
We're going to ignore the best practices listed above for educational purposes only, as you will of course re-factor this after learning how it works.
Your goal (from what I can gather): to have the correct table name available within the base class Model
, depending on which object is currently extending it (User
or Post
).
abstract class Model
{
/** Child classes MUST override this (you can enforce this if/however you like) **/
const TABLE_NAME = "";
public function __construct()
{
printf('Created table: %s', static::TABLE_NAME);
}
}
So far, you have a Model
object that can't be instantiated directly because it is abstract. Therefore, it must be extended to be used. Cool, let's create your POST object.
class Post extends Model
{
const TABLE_NAME = "POST TABLE";
}
When you create the Post
object, it'll use the inherited constructor from Model
. In the Model
constructor, it uses static::
instead of self::
to echo the table name. If it had used self::
, it would have echoed 'Created table: '. Instead, because static::
, the inheritance-aware version of self::
is used, it uses the inherited var instead.
So the result of calling $post = new Post;
will be "Created table: post".
Assuming you create a User
object too:
class User extends Model
{
const TABLE_NAME = 'User';
}
Each object will have it's own table name echoed when you create them:
$x = new User; // echoes User Table
$x = new Post; // echoes Post Table
Conclusion
You don't have to do this with constants (although, I would). You can do it with class properties. But don't make them public (global mutable state is bad).
With the above information, you should be able to easily have a getSchema()
method that uses static::SCHEMA_NAME
in the getSchema()
method for both Post
and User
.