I think you're trying to build a framework that is too tightly tied to names and concepts. I've found the names and concepts in the Model-View-Controller idiom are not rigidly defined. I've also found that code working in that paradigm needs to be able to bend the rules sometimes.
@duffymo has a very important point about the Model component: a Model isn't a Datastore, it just has a Datastore. If that is not clear, another way of thinking about that it is to look at what an instance of each is supposed to be. An instance of a "datastore" object represents a resource which mediates access to an arbitrary amount of data. Usually it is a database connection. An instance of a "model" object is usually a discrete identity with multiple pieces of data. Usually it represents a database row in a table, but it could be a line in a text file, or one file in a file-store.
Applying the same quesion to the Controller and the View and you can see that the Model part is quite a different animal. Whilst only one Controller object and one View object will normally be in existence at one time, it is quite likely that several different Model objects of different types are in existence at one time.
Unfortunately, I also know that a lot of MVC "frameworks" define a "Model" as an API layer behind which you do SQL statements. In those frameworks, a "Model" is a static class or a single instance and does nothing more than provide near-useless namespace partitioning. And a lot of programmers think this is supposed to make sense and struggle with it. This is why I recommend you don't use the names and concepts of the MVC idiom.
My preferred way to write structured PHP only nods to the MVC paradigm. It has dispatcher and controller logic in the top, and HTML markup in the bottom. This works well because Controllers and Views are often tightly coupled and putting them in the same file is very PHP-ish. Yes, it does take discipline to not do controller-ish actions in view-ish code, but I'd rather have to do that myself than have the framework force me to. These pages don't stand alone, however, they include a lot of common logic and can import things like a lightweight dispatcher system, or even call whole swathes of common controller logic.
But the main thing the common logic provides is a data-abstraction layer -- basically the Model layer as described at the top of my answer. The data-abstraction layer I wrote is basically three things: a database handler, an "object" object and a "collection" object.
The database handler is the DataStore for all objects that live in the datbasee. It's main purpose is so that activities to the database that aren't making a query and getting a response are all in one place. Most database calls are in the object core. The database handler doesn't know anything about the object core: it just takes SQL and returns resultsets.
The other two objects are designed to be sub-classed and will not work if instantiated themselves. Using inheritance and a special extended declaration (done by a static class method), they know how to turn
database data into an object. An instance of an inherited "object" object represents one row of the declared class. It is given an ID upon instantiation, and will query the database when it needs to to retreive its one row of data. It also keeps track of changes and can do a one-row UPDATE when told to. The API it presents is completely devoid of SQL: the object has fields you ->get() and ->set(), and you can ->save() when you're done.
The "collection" object knows how to get a filtered list of rows of a particular object and knows how to turn that into individual objects as appropriate, each of which function just like they were individually instantiated. (The collection object also supports being an object itself, but I rarely use this feature as it currently has some implementation limitations. And it's a concept I've found most programmers have trouble grasping.)
Most objects need only the core inheritance code and the declarations for their specific table.
The end effect is that the controller code gets to do obvious things like this:
$ticket = Ticket::Create($ticket_id);
$ticket->set('queue', $new_queue);
$ticket->set('queue_changed', date('Y-m-d H:i:s'));
$ticket->save();
... instead of something opaque like:
TicketModel::ChangeTicketQueue($ticket_id, $new_queue);
This approach also lets you code things in the Ticket object that might update other fields or other objects when the queue
field changes, and it will always occur when you change that field, instead of having to remember to do it in every function that can change a ticket's queue. It also means you can add other methods to a Ticket: it would probably make sense for $ticket->get_queue()
to do return TicketQueue::Create($this->get('queue'));
for you. Object oriented programming at it's finest! :-)
So, to finally answer your question, I would recommend none of the approaches in your question. Your model objects should present a unified API to the controller code and it is up to them as to how they store their data. If it is in a database, then they need to organise their own calls to do that. But a model isn't a datastore: however, it may well have one.