There are so many PHP frameworks on the market, some with a immense popularity (Symfony, Laravel), so why bother to create another one? The answer is simple: they aren't good enough! Any software should serve its end users first and foremost, which means when developing a framework performance concerns should come first instead of becoming a sidenote. Secondly, it should serve developers by being simple to learn and build on its foundation. Thirdly, it should be an occasion for its creator(s) to build yet another piece of beautiful efficient code.
Bad frameworks are completely at odds with all above requirements: they are extremely slow, poorly developed and needlessly difficult to use. There is nothing to commend about them except an army of coders that hang on it as their life line!
They attempt to increase development productivity by extending project skeleton so much that little is left to its users except learn and apply. The consequence of this decision is them becoming huge and potentially very slow by executing far more logic than strictly required.
A handy solution against slowness would have been modularity: building complexity on the horizontal scale (breaking up functionality into pluggable apis). Unfortunately, none of these frameworks take this decision except on paper: you only need to take a closer look at Twig, for example, to notice it depends on entire Symfony framework!
The end results are visible in TechEmpower Benchmarks (where Symfony or Laravel situate at bottom). Please note that owners micro-optimize their frameworks there to up their rating: most of optimistic numbers are impossible to reproduce in independent benchmarks! The general rule in benchmarks is NOT to trust others and always make your own!
One of greatest advantages of object oriented programming is encapsulation. It gives developers an ability of breaking code into standalone units and, since that is the essence of good code, popular frameworks such as Symfony or Laravel went over the top trying to achieve that.
One problem with encapsulation is that very few developers know how to do it properly (you can judge that by how simple code they produce). Another is over-abstraction based on dogmas or fears of needing to extend functionality in the future. When poor encapsulation skills meets over-abstraction the end result is bloated code, hence plenty of logic to execute something that should be trivial.
Let us take Laravel's App\Http\Controllers\Controller example: why are all controllers bundled with AuthorizesRequests logic? Some applications and project resources do not need this at all, not to mention this should be OUTSIDE a controller's concern. Controller should take resource level decisions and other higher scale models should concern on application level ones (such as AuthorizesRequests)!
Another bad decision visible above is the usage of traits: for some reason PHP introduced this multiple inheritance feature and some developers (worse still, framework developers) hang to it as a life saver. By designing classes properly and delegating responsibilities (the good old Strategy Pattern), however, you will never need traits and code will remain pure and logical.
The answers to this are two fold: on one side, you really have a complicated product that tries to achieve everything. On the other, however, the way it is designed is in itself a problem: if you have a more complex issue (for example in Symfony adding a controller failed with a cryptic error), there is no chance for you to debug it unless getting yourself lost through the endless maze of abstractions.
One of the reasons for their popularity is their ability to transform everyone into a coder as long as they learn how to apply framework's recipes. Anyone can learn and apply, but at most they you will do it mechanically! Since humans are bad machines, they will seldom have patience to learn the process fully while at the same time lacking training or intellectual skills to fill the missing gaps.
To counter this dire side effect, a do not reinvent the wheel dogma was created. Coders are encouraged (for a very good reason) to learn framework better or use libraries over the net instead of trying to build their own (mess). Once lazyness kicks in once again, however, the end result will still tend towards that typical bloated over-programmed mess impossible to work with (unless draconian measures are taken).
Good frameworks adhere to preamble principles by being built with performance and simplicity in mind. Code inside is small, by virtue of being encapsulated on natural principles and applying less is more methodology. To achieve this, following measures need to be taken:
They are not designed for coders unless they want to become programmers (and have the intellectual skills to do so). You will be expected to "invent the wheel" whenever required and keep your project as well ordered as framework underneath!
Lucinda was originally built using Spring as model (an excellently designed leading Java web framework that applies all concepts above), then diverged drastically to fit something closer to PHP development and author's own creative ideas. It strives at being a good framework by applying minimalism and modularity in order to obtain high performance and scalability.
Let us take Lucinda's Lucinda\STDOUT\Controller example: unlike Laravel, MVC functionality is delegated to a dedicated STDOUT MVC API instead and no behavior inside is bundled. This class only contains pointers to models already initialized by API (to be used when needed) and requires you to respect Lucinda\STDOUT\Runnable contract.