PHP applications without ORM's - sharing expierience

Some time ago I wondered how writing a larger application would work without any ORM - I started a thread here to gather some input from others and finally decided to give it a try. After first attempts in very small personal projects I set out to create what I would call a medium sized application for use in a network of companies from different locations and its main goal was to manage order processing between car services, car owners, etc., including statistics reports and so on - there were quite a number of intricacies to how it was supposed to work but I won’t go into details since they are not relevant. The application has been up and running for a few months and being constantly worked on with new features so I would like to share my experience how I feel about not using an ORM - and hopefully gain other people’s opinions and insights!

1. Back to plain SQL

As a way of interacting with the database I chose Doctrine DBAL, which has a nice set of utility functions for interacting with databases and is a very light library. It also has functions for query building but I didn’t use them. I actually liked using plain SQL for everything, especially that I chose to discover Postgres and its unique features so abstracting SQL would have been unhelpful. I noticed that even writing simple CRUD statements was not really tedious and I didn’t miss an ORM’s simplicity here.

2. Application Model

For me this was the biggest thing that stood out - without an ORM library I had no models to start with, nothing generated for me. I had to do it all by hand and it made me think really hard about how to write the models and how to structure them. On the plus side I could create them exactly tailored to the needs of my application without any unused redundant stuff.

After investigating a few articles on model architecture I decided that my model layer would be composed of independent service classes that would provide an API for interacting with the outside world - the API would provide just the methods that my application needs. The outside world for the models in this case are mostly controllers (they could be the views also) and the controllers tell the models what to do based on the request data. The models would contain most of the application code.

Now the models would need a way to communicate with the database somehow. The ideal solution, I thought, would be to split the model into two layers:

a) the outer layer containing the main business logic
b) the inner layer containing an abstracted way of communicating with the database

This structure would make my application independent from the way I access the database - I could use plain SQL or I could use an ORM of any kind - the inner layer would translate it all to the proper underlying database library.

However, I didn’t go that route because the amount of work for creating this kind of abstraction didn’t justify the benefits in this case. Switching database access library seemed like an extremely unlikely scenario so I simply chose a shortcut: I created a single model layer that had a dependency on DBAL and it simply used plain SQL via DBAL to interact with the database. So most model classes would require the DBAL object via dependency injection.

3. Fewer objects, back to arrays

Because of lack of ORM the data fetched from and sent to the database are in array format. Using dumb stdClass objects would make no sense in a situation where these objects are not defined anywhere. Therefore, I deal mainly with primitive data structures - this is certainly some drawback but not a huge one. No code completion, etc. however, more freedom to do anything I want with these arrays. I can fetch any additional data using joins, sql functions, stored procedures, etc. without worrying how to hydrate existing stiff ORM objects with them - I just add new columns to fetch, or values, or whatever I like, and the array won’t complain.

Because I’m dealing with primitive data then all necessary data manipulation, formatting, etc. is moved to outside modules (classes) and I use them. Not a problem really and perhaps even an advantage since I’m pushed to build small independent classes with single responsibilities.

4. Simple CRUD

Simple CRUD stuff required a bit of manual coding but it was not that tedious after I had it ready for the first table/model. I used to use a framework that auto-generated the CRUD stuff for me, which was a bonus. I think I might need to think of a code generator for the simplest CRUD.

5. Overall complexity dealing with database

If I were to compare then to me the overall complexity is smaller without an ORM. It’s true that I lose some small conveniences when dealing with simple CRUD but on the other hand I do not have the whole ORM library that I have to deal with, learn and use. Such libraries are not (usually) small and using them also requires time and expertise.

Also, I get rid of all the magic that an ORM does behind the scenes so I found my code became actually clearer. But it must be noted that I like and enjoy SQL, which has always been clearer for me than a bunch of object oriented ORM commands. Not having to think about how to use an ORM with relations is also sweet - just write a join SQL and fetch the necessary data without any problem. Adding new columns to the database is also very simple - no need to deal with XML configurations and the like - just add a column and use it right away.

6. OOP

Paradoxically, I found that without an ORM my code became more object-oriented than before. That is because despite dealing with primitive array data I am more pushed to create all the OO components that deal with the data and behaviour. The data structures became more primitive while the code around them more object-oriented.

7. Final thoughts

To be honest after these months of dealing with ORM-less code I’ve fell in love with this coding style and I feel quite a relief. There are a few minor disadvantages but to me they are outweighed by the greater simplicity and clarity of code. The code is more dependent on the database than with an ORM but this is not a problem in projects that are not meant for database switching. I don’t think this coding style is for everyone since there are certainly people who do not like SQL so much. Personally, I’ll continue with this in my next projects and will try to still improve on some things that might be done better.

And some technical stuff: the project is based on the Silex framework - I wanted something minimalistic that would not get in the way. Actually, I made the application as framework independent as possible so I could easily take all the controllers, models and views and move them to another framework with relative ease. The framework does not matter much.

If anyone has comments or opinions on this then please share. It is always a good idea to hear other approaches even if we don’t choose to follow them!

2 Likes

Great Post!, I myself also came to that same realization that today’s ORM’s are just to much for many of the applications being built with them. Granted there is mixed feelings and really project depended needs that i take into consideration when building applications that interface with a database.

My concerns are the extra baggage that many of today’s ORM’s carry with them. For a sinlge simple select query an ORM like doctrine will load up many different classes to accomplish the very thing i could do with 1 line of code.

Now i do believe a certain level of abstraction is needed and things like PDO or other DBAL’s can be a benefit when needing to switch out database vendors or you use multiple venders and some of the sugar syntax can be very nice to have at hand.

But ORM’s are for the developers who can’t work with data they only know code and that’s all they need with many of the ORM’s out there. But in a real business environment i have never used an ORM unless it was hacked on as a second thought like most and that was for the less experienced developers who couldn’t write advanced optimized query’s.

So looking at the code of a ORM you have many layers before the real query is even executed you have the Model layer and the OBJECT layer and then the abstraction layer and then the query will execute. Seems like alot for really only a few lines of SQL…

The modern development world of php is spaghetti that is why the PHP-FIG was created to start getting some kind of similarity between code and what and what not should be used in your code. To many kids think they know more on how to develop than people with 10+ years that is why everything is abstracted away and the php language is abstracted away to syntactic sugar. Because they think its better and once they become a true developer where they know they tend to revert back to a more logical and real way of developing with KISS(keep it simple stupid).

C++ had this problem back in the day as well with everything using templates and creating sugar syntax and now that has seem to gone away for KISS approach but there is always going to be those guys with less experience thinking they know more about code because they can write a large class framework…And the other kids learning code listen to them because they wrote a framework or an ORM or some other stupid class library that abstracts away the stuff you can do in 6 lines to stuff that takes classes and classes to do…

I have been programming on the side of 15 years now and i know many of the most used languages in the world. And this is not a code problem but an inexperienced problem.

Another example of this is the creator of php rasmus a few years back mentioned codeigniter was a brilliant framework and better than many of the larger frameworks out there. I agreed but he was critised for saying that and blasted hard. But this is the guy who created the language, knows the underlying language and has years and years of experience. But he was right and the morons blasting him are just script kiddies that can only code php and have no idea about how a language works or is built or why its better to do something and not others.

So it sounds like you are starting to learn the real nature of development and how it should be done. I welcome to you to the dark side!!!

1 Like

I have been doing something similar.

I use the Doctrine dbal component as well and while most of the time I just write plain sql I do find the query builder to be useful when building queries with lots of optional where conditions. Building up complex sql strings by hand is no fun.

I just can’t bring myself to inject the database connection into my entities. I know plenty of people use the active record approach but I got spoiled by keeping my entities database ignorant. Just seems cleaner.

So database access is through individual Finder/Updater classes. Each entity has a static createFromArray() factory method which maps sql array query results to the entity properties. Seems to work okay. Here is an example:

One thing that motivated me to drop the ORM approach is that Doctrine makes it a bit difficult to have multiple version of the same basic entity. In my application I have several Game classes each defined with just the properties needed for a specific set of actions.

Be great to see some of your code. Especially the active record portion. Might be time for me to take another look at it.

Yes, I didn’t mention the underlying complexity of an ORM but it certainly has a performance impact. But there is a reason to that: object relational mapping is so difficult (almost impossible) so that in order to get it to work even in 80% the library must be very complicated.

The developers also are burdened with learning all the many features of something like Doctrine and the additional library can be another point of failure because it can have bugs - just like anything else written by humans.

I wouldn’t be so harsh in saying those developers can’t work with data - they just think that it’s better to work with objects than dummy data structures like arrays and they want to make everything object oriented including data.

I have noticed there are two main approaches to handling data:

  1. Database centric - start work on the application from building the database and then build your code around it.

  2. Model centric - start with the model, describe what objects are needed for the application and then build the database to be able to hold the objects. Then for a relational database an ORM is obviously needed and often the ORM may create the database automatically based on the defined model objects.

I have always worked with the first method and the second one has always felt to me backwards. If application data need to be in the form of objects then we should be using an object oriented database instead of using monstrous and imperfect ORM’s.

When I was pondering if I should switch to the second option or not I read an opinion of an experienced programmer that in the world of long-lived applications their most durable part is the database. Sometimes the application code may be changed and rewritten but the database is what survives.

You are saying you dropped the ORM approach but from your code it looks like you are using an ORM - just not Doctrine but your own (simplified) version. Your Game class in an entity object that holds the data of a game and you load the data from a relational database in the createFromArray method - so in effect you are mapping objects to relations, aren’t you?

Do you mean you would like to see the active record portion of my code? There is no active record in my code, no ORM of any kind, I thought this was clear from my post? :smiley:

BTW, how are your entity classes created? Do you write them by hand or are they auto-generated to some extent? What happens when you add or delete some columns in the database - do you have to update all the related entities at the same time?

I have always found that people who don’t like ORMs or abstracted code to that level of complexity just aren’t smart enough to understand it. Do you use smart debugging tools? Using smart debugging tools makes a big difference understanding other peoples people code. It’s really easy to write your own your code… I mean of course you understand what you wrote. It takes a true professional to understand to what other people have written, utilize it for their needs, and of course modify it for their business requirements. Different strokes for different folks but I prefer all the wonderful advantages of a well known ORM. Especially. When it comes to handing off the project to someone else. How much documentation have you have written for this project. My bet is none… neither does it have any type of community around it. So the second you leave the company whom you created for is essentially up the creek. Think about someone else besides for yourself. Like the next person who is going to see your code, has to deal with it and has no documentation or community to lean on. I’ve worked on so many projects where 10 to 20 hands of worked on the project and this type of stubborn, rebelious behavior ALWAYS hurts projects long term. You never write and documentation and code the project as if you will only be the only person EVER working on it. Grow up.

I prefer all the wonderful advantages of a well known SQL-Standard, everybody can read it, no need to learn specific ORMs. Most of the other things you mention are just guesswork, not arguments.

1 Like

Probably right. I certainly don’t claim to be particularly smart.

On the other hand, I have used Doctrine 2’s ORM since it was in alpha. Six or seven years ago? I have read through the code a number of times and consider myself to have a fairly deep understanding of it. I also have several hundred Doctrine related accepted answers on stackoverflow.

The thing is, no matter how well designed a component is there are always use cases where it comes up short. For example, say you have a user and a user profile table with a one to one relation between them, You want to have the same primary key for both because that is the way your existing database was setup. Somewhat surprisingly, Doctrine 2 does not support this out of the box and actually requires you to jump through some pretty serious hoops. And even if you hack in a solution would your hypothetical successor automatically understand it?

I have avoided doing so for almost 60 years now. Hopefully I can continue to do so.

1 Like

@ahundiak i do not agree with what your saying at all. Lets say i give you a new ORM you have never used or seen. And ask you to write up an advanced query pulling from 2 different database vendors and using 6 different tables. Your starting point would be you need to be learn the sugar of the ORM through documentation and then begin writing your models. So instead of now just needing to know SQL you must also learn an ORM syntax and structure. ORM’s are not the standard in development sure anyone can learn them just like they learned SQL but the problems comes is it required to complete the task at hand and 99% of the time its not a needed tool in a developers bag when working with data. But SQL is 99% of the time is a needed knowledge. So if they is a new developer and working on code just handed to them the expectation is they should know SQL and Database Structure and that is all they should need to work with the data. And if you think about it from a database perspective SQL already abstracts away the underlying code to make it easier to work with the data and then you add an ORM on top that? Wouldn’t it make more sense to just use a noSQL database. Its all about the tool for the job to me and SQL is a standard tool needed an ORM knowledge is not needed but ether way both can be learned.

1 Like

I think you meant to direct your post to @allornothing85?

allornothing seems to feel that the only reason that some developers chose not to use an ORM is that the developer is too stupid to understand it. For some reason the same developers are too stupid to use smart debugging tools as well but I digress.

You on the other hand seem to feel that ORMs are for developers who can’t work with data. I was a bit confused when you said early on that you could replace a typical ORM with one line of code and then, a paragraph or so later, indicated it would take several lines. I guess that is part of learning the real nature of development.

I did get a bit of a chuckle out of your C++ remarks. I use C/C++ in my day job and, at least in my universe, any C++ developers without a deep understanding of templates won’t last long. But again, I digress.

I like to consider myself as being a bit more moderate. ORMs work great for many apps but you also need to be able to fall back on straight sql when needed.

I don’t think it makes sense to argue with @allornothing85 - it looks like he needed to vent and feel superior so he made up a few unrelated assumptions just to do that so I consider his post mostly off-topic (and his account appears to be banned so he must have done something to anger the moderators).

I’m still undecided what to think about ORM’s in general, it certainly is a coding style that some people like. It is nice to use them for the simplest CRUD and the syntax may feel more elegant and object oriented but I don’t think this justifies for me the necessity to learn and know all the intricacies of the ORM. SQL is a standard so anyone looking at it immediately knows what it does and if there is a problem to test I can copy it easily and run directly on the database.

I consider the database to be a much more permanent element of an application than an ORM, which is constrained to one language only. If an application grows it has the potential to have clients in other languages than PHP connecting to the database and doing their job and then there is no uniform way to interact with the data because PHP will do it with its own ORM, Java with another one, C++ maybe without one. Now from my humble experience I can say that an ORM doesn’t help with handling complex applications whereas having more SQL in the code provides more clarity and makes things simpler - at least for me.

My current perception is ORM’s are not entirely useless but certainly overrated!

1 Like

That’s my take as well.

Rails is great with Ruby. Learning ActiveRecord can be a bit of a learning curve. but I think once you understand it, it should be easier to learn other ActiveRecord type ORMs. And once you get one down for your language of choice I guess it could reduce dev time, though in a lot of instances it seems more like a “preference” than a “need” (well, unless you’re not working solo).

But the common denominator is working with the database.
Once you get past the “design with everything in one big table” stage and can put together more complex queries, I think that pretty much eliminates the need to have to learn and use imposed conventions for your own code.

I’ve just come across an interesting article about ORM pros and cons presenting very sound reasoning behind his statements: ORM anti-pattern series. I especially liked part 4 where he talks about structuring models and what they usually look like when using ORM’s. He seems to have more experienced than me with large applications so it was an interesting read.

I would disagree that I am using an ORM. Following the terminology from a set of articles you posted (thanks by the way) http://www.mehdi-khalili.com/orm-anti-patterns-part-4-persistence-domain-model/, I would classify my game entity to be a domain entity. I then use aggregate root repositories to interact with the database. I also more or less follow CQRS (Command Query Responsibility Segregation) to divide my repositories into Finders and Updaters.

One difference to this approach as opposed to most ORM approaches is that my domain entities seldom map directly to database tables. For example, I have tables for game_team, pool_team, tournament_team and physical_team. In most cases, all I need is a domain team object which happens to be composed from assorted portions of the various tables depending on what the request needs.

I have tried keeping my data in arrays and still do so in some cases. But losing the auto-completion is a major problem in maintainability. Furthermore, when my domain entities do have behavior then adding the behavior directly to the entity seems cleaner than creating an independent function.

Indeed, I forgot about the distinction between persistence model entities and domain entities as mentioned in the article. So I agree your entities are different from typical ORM entities that map very closely to the database schema. But then I’m not sure what the definition of ORM is and whether we understand the same thing by the term?

If I forget about existing ORM implementations and treat the term literally, that is mapping objects to (database) relations then to me the code you presented is an example of a perfect ORM because the mapping is tailored exactly to suit your business logic needs. There is no direct mapping between your entities and database tables but is it necessary for an ORM? If there is none then I’d say it’s even better because you get the true (object oriented) domain model based on your business needs on one side and a relational data store on the other. I’d say this is an example of a perfect ORM because the object-relational mapping is perfect and there is no unnecessary bleeding of relational schemata on the domain model’s side. If you follow CQRS then I think this makes the mapping even better. But then again - I’m not sure if that would fall under the term of ORM.

The problem with this is you have to code it by hand because no ORM library can do it automatically - which on the other side is a plus because this kind of domain is composed of much more useful entities than those that might have been generated by an ORM library or been a part of an ORM’s persistence model.

I’m certainly willing to accept a description of perfect. Though modesty prevents me from doing so.

While the M in ORM stands for Mapper I have always considered it to mean more of a Manager. Some system whereby you can do CRUD type operations with little or no additional hand coding. M could also stand for Magic as it tries to abstract away as much of the database interaction as possible.

Going back to your original post, I gather the main difference between our approaches is that you map arrays instead of objects? An ARM perhaps?

IMO, an ORM is an abstraction layer to hide the complexity of SQL queries. So, one can easily interact with the database even without having a deep knowledge of SQL query language. So yes, everything comes with a trade off. It depends on the context of your application what should you use and there is no golden solution for every problem. Many developers can build complex apps even without writing complex queries by hand and that’s the power of an ORM. So, it’s a fair trade off (IMO).

Because that’s what ORM implementations come down to most often. However, to me ORM in its broader sense is not only about CRUD but about all operations - and that’s why I considered your example a very good hand-made ORM.

I’ve also been thinking about this kind of abstraction recently and wondering how beneficial it really is. The obvious advantage is that we have an object oriented domain model to work with. But the disadvantage is that we, the programmers, have to deal with two models: the domain model and the relational model. In an ideal world the ORM would take care of the relational model transparently but that is never the case in practice apart from most simple cases. So in a more complex system it is not only the ORM that has to do the mapping but also the programmer who needs to do the mapping between the objects and relations in his mind while coding. Otherwise, ignoring the existence of the database might lead to serious problems.

ARM sounds really great especially for such a primitive implementation :smiley: This is an area I’m still undecided upon and for the time being I’ve decided to experiment to get back to using plain arrays for dealing with data. The reason why I’m undecided is because I’m seeing both pros and cons on both sides.

Pros of entity objects:

  • object has a defined signature (properties and methods) so it’s easy to see what kind of data it holds and what it can do
  • IDE autocompletion
  • ability to add documentation to any property and method via doc blocks
  • can be type-hinted in arguments

Cons of objects:

  • they have to be written, which adds work (ORM’s do a lousy job with it unless for very simple cases)
  • when we want to add a field to be fetched from a database table we not only need to change the SQL but also change the entity (add the property)
  • managing entities adds some complexity to the system
  • slower than arrays - for single entities there’s not much difference but if we fetch a long list of records from the database and then have to hydrate all of them to separate objects the overhead can become significant and we may exceed memory limits (I once hit the memory limit when fetching data into objects for a large table)

At the moment I just want to see if I’m going to miss objects when dealing with data. So far I can say - not so much. One set of pros and cons has been replaced by another but the system is simpler.

Here is an example of a simplest model that I may be using currently:

class CarModel {
    private $db;
    private $carValidator;
    
    public function __construct(Connection $db, CarValidator $carValidator) {
        $this->db = $db;
        $this->carValidator = $carValidator;
    }
    
    public function getForWeb($id) {
        return $this->db->fetchAssoc("SELECT name, model, color, owner
            FROM cars
            WHERE id=? AND NOT hidden", [$id]);
    }
    
    public function getForAdmin($id) {
        return $this->db->fetchAssoc("SELECT id, name, model, color, owner, hidden, added_date, modified_date
            FROM cars
            WHERE id=?", [$id]);
    }
    
    public function fetchList() {
        // when being very lazy I use SELECT * - I know, not very descriptive!
        return $this->db->fetchAll("SELECT * FROM cars
            ORDER BY name");
    }
    
    public function createFromForm(array $data) {
        $errors = $this->carValidator->validate($data);
        
        if ($errors) {
            $ex = new ValidationException;
            $ex->setErrors($errors);
            throw $ex;
        }
        
        $this->db->insert('cars', $data);
        return $this->db->lastInsertId();
    }
}

My model contains specialized methods that my business logic needs and it gets and writes the data in array format. Sure, the models are then dependent on the database schema but there is only one structure to work with: the relational structure from the database - there are no entities that form another layer of the domain.

When working with domain entities I believe it’s important to have separate specialized entities for each context - like in the example the methods getForWeb() and getForAdmin - the different usage contexts require different sets of data so they would need to be transported via different entities. There’s no need for that when using arrays.

I’m not saying this is the best approach but I’m trying out the simplest one at the moment and so far I don’t see much of a problem with that. Sure, the data is not supported by a descriptive skeleton of entity classes and I have to look at the database schema from time to time but this is not much of a problem.

However, I’m willing to discuss this further if you have an opinion one way or the other.

That’s the crucial question - is the trade-off worth it? This is subjective but now I’m trying out whether it’s worth for me at least.

Not a whole lot left to discuss. It is subjective. In my experience for my apps, domain entity objects win hands down over domain entity arrays in terms of robustness and maintainability. You listed most of the reasons.

To me this is a big deal. I don’t want to have to look at the database when dealing with most of my app. Ideally the code should not even know there is a database lurking somewhere in the background.

You mentioned “descriptive skeleton of entity classes” and that is exactly what I try for. The are many developers who seem to feel the oop requires making class properties private and that the only way to access these properties is through getters/setters. So a simple class with 10 or so so simple properties suddenly blows up into several hundred lines of useless code. And of course you end up with $car->getName() instead of $car->name in your application code. Get rid of that nonsense and making skeleton classes becomes much easier.

And of course having classes instead of arrays can eliminate a huge source of errors when combined with a decent ide.

I agree 100%. But again making two car entity classes is worth the effort.

I really don’t like using SELECT *. What actually have you gained? Sure you end up with the new field in your array but don’t you actually need to use it somewhere? I almost always end up having to change my app code when I change the database schema anyways.

Managing array functions adds even more complexity. Unless your entity arrays are truly just data transfer objects then you will find that somewhere along the line you will need to do a bit of data processing. With objects you can add methods. With arrays, you need to add functions somewhere.

Assume your car has tires. Implement:

$car->getSpareTire();

using array entities. Can turn out to be a bit of a pain.

But again there is a great deal of subjectivity here. The real test is when you come back to a project after a few months. Can you still figure out just what the heck you did and can you confidently make changes without the fear of breaking things?

Maybe not a whole lot left to discuss but I just wanted to know your opinion on this matter, which you presented very well, so thanks for that. BTW, I’m not arguing against your way of doing things, actually when I think about a sensible way of handling data in object structures then an entity system like yours looks like most sensible to me and I might actually use it in the future.

This strengthens my perception that you are actually using an ORM :smiley:

And don’t pick me up on SELECT * - I’ve already admitted it is not a good idea!

This is another thing that I’ve been thinking about - what kind of data processing methods fit well into the entities? Data formatters, format translators, etc? A few times I’ve been bitten by putting too much behaviour into my data objects and after some time the objects became huge with lots of methods that were tightly coupled to one object and impossible to use elsewhere. But then I was using one object for all kinds of contexts in the application, which could be the reason for the mess that began happening with time.

For arrays my solution is simple - the model methods that fetch data do all the necessary data processing - directly or via external services. If some kind of processing needs to be done in multiple places or is a bit complicated then I create a separate processing service (a class) that the model uses to process a certain data format or structure.

Is this supposed to fetch a related object, which would normally be from a separate table joined with a FK? I’ve had this requirements in my apps when using arrays and this has never been a problem - I simply used a JOIN to fetch all needed related data and that’s it.

How do you handle the getSpareTire method behind the scenes? To me this is where the complexity begins: has the spare tire been fetched by a JOIN somewhere earlier or is it fetched on demand? If it is fetched on demand then this may increase the number of separate sql queries, which is not always good. If it is fetched with a join then too much data may have been fetched than necessary. Also, there needs to be some database communication behaviour baked into your entities to fetch related data (which you already showed in your code example).[quote=“ahundiak, post:18, topic:238732”]
But again there is a great deal of subjectivity here. The real test is when you come back to a project after a few months. Can you still figure out just what the heck you did and can you confidently make changes without the fear of breaking things?
[/quote]
Yes, this is subjective. I have not yet had such a long break from this larger project of mine but for about 8 months I’ve been working on it in a casual maintenance mode from time to time and when I come back to some parts coded a few months back I’m not lost at all. To be honest, it all looks much clearer than active record ORM I used a while back. I don’t have a direct comparison with a nice entity system like yours but I can honestly say using plain arrays in not a huge pain if the system is coded right. And yes, I need to peek at the database from time to time to find my way around but I don’t see why this would be a problem.

Thanks for the feedback.

Probably not as much as you think. When I created Maphper ( shameless plug: https://github.com/Level-2/Maphper ) it sort of avoids this issue, insofar as you don’t need to design the entity class to have knowledge of the relations. or even as a concrete class you can do this:

//map to databse
$users = new Mapper(...);
$users->addRelation('address', new One($addresses, 'id', 'userid'));

echo $users[123]->address->city;

with either stdclass or class User {} as your entity class.

Of course this relies on a bit of magic. After running SELECT * FROM users WHERE ID =123 and building a the relevant $user object, it creates $user->address which is a object that basically does this:

class RelatedFields {
    public function __get($field) {
        $address = $this->addresses->find(['userId' => 123]);
       return $address->$field;
   } 
}

It’s a bit more complicated than that but the upshot is that without configuring any entity classes you can basically do this: echo $user[123]->orders->item(0)->deliveryAddress->city.

Whether or not to create concrete classes for entities or not is an interesting discussion, personally I am against it and imho if you can replace your entire ORM with json_decode() then you’re better off because it means your application code is coupled to a data structure that could be generated anywhere than to specific database/orm implementation.

I’d rather have a function that takes a data structure and works on it, than takes an object and extracts data from it using whatever methods and probably law of demeter violations. We can talk about encapsulation but this is purely pragmatic: If the function works on a data structure it’s not coupled to any other library and is therefore more portable. I can move the function to another project that grabs data using json_decode() and it will just work.

This is an interesting article http://www.smashcompany.com/technology/object-oriented-programming-is-an-expensive-disaster-which-must-end I don’t agree with a lot of it, but the parts it mentions about data structures are spot on.