In true JavaScript fashion, I decided to learn PHP again by building a framework to put all the pieces together in my brain.
I absolutely love Hono.dev, and decided to base the PHP framework on that. Dumbo isn't intended to compete with Laravel, Symphony or Slim, if anything, it's something people can use in production, but also contribute to and be used as a learning resource for others.
``` /* @var array<string, mixed> Variables stored in the context */ private $variables = []; ```
This should be typed as `array` (heck, I'd argue ArrayObject instead) and all your classes should have `declare(strict_types=1);` at the top.
Your `Dumbo\Helpers` classes are basically static mine traps that you are unable to mock in unit tests. Why does `BasicAuth` expose a single static method but then calls a bunch of other static methods? What ends up happening in any class that uses any of your `Dumbo\Helpers` classes will always run whatever code is defined in these helper classes.
I'm unsure where the bootstrapping process begins. What file does your webserver need to call to handle a new request? I am hoping it is within a root-level directory and not at the root level itself. In other words, `/public/index.php` vs `/index.php`. Your quickstart in README.MD makes it pretty clear that you expect the latter, which is highly unsafe. See any number of poorly configured webservers that stop processing PHP for any reason but now show your site's full contents to anyone passing by.
I would strongly argue against _any_ magic in your framework. Specifically, routes: they should be explicitly defined. I still work with a legacy Symfony 1 framework project and I can't tell you how much I detest magic routing. For a modern example see how Symfony 2+ requires explicit route definition. Heck, how it requires explicit everything because magic should be left to magicians.
Your framework seems like it can only handle `application/json` and `application/x-www-form-urlencoded` requests, but not `multipart/form-data`.
Take these as positive criticisms of your work. It's "fine". I wouldn't use it, I would actively recommend against using it, but I would actively recommend against using anything that's not Symfony (or Laravel if I were drunk). I do not think your project is at the "Show HN" level - it is still far too under-developed.
I can (and have!) gone in-depth into my misgivings with Laravel, but it is fine for most projects and teams. It has elevated the average codebase quality throughout the PHP community and introduced many engineers to what PHP can do. Its creator and community have been a large net-positive to PHP as a whole.
I still prefer Symfony:
1) explicit 2) DataMapper ORM by default 3) What I am used to
A simpler framework with modern techniques would be great though.
Just because someone wrote a book about patterns, it doesn't mean it's the high standard and the holy bible by any means. These people are mostly control freaks, who like to exert control on people and think their excrement is akin to a lump of gold.
And then there are the preachers - like you - who disseminate the bullshit these pattern monkeys rant day and night.
We still have a lots of legacy PHP, but its slowly being refactored to Haxe. With Haxe we get a really nice typesystem, and a "faster than Go" compiler. It has pushed our productivity thru the roof.
We still need to use external dependencies tho, as PHP lacks any concurrency in the core language, so we also have a Go API for fetching data concurrently, and also use it as a BI directional socket for the frontend and as a queue server.
Otherwise, the stack is pretty much PHP7 from top to bottom.
Basically we generate code in our src folder under a reserved namespace, and other PHP code can then use that code with imports. As we grow, we might want to split this into separate compilation units (we are not there yet, as the Haxe compiler is really fast!)
At the moment the generated PHP code is checked in source control, again we might want to have this done in CI, but it works kind of nicely at the moment.
The tricky bits are how to "speak" to PHP. Haxe is a really nice functional language (even its syntax is traditionally class based, but you can have module level fields in Haxe since 2020), so its pretty annoying to handle option types etc from the PHP side. We are still not decided on this part, and many APIs expose duplicate functions for some general task, like foo and foo_exn, and the one that ends with _exn throws instead of returning a variant (like option/maybe etc)
Also, its tricky to design where data is fetched from. We tend to keep the Haxe code as pure as possible, and only taking input and returning output (not doing any IO). We also write our own typings for externals, this has actually been really good for us, as we can observe easily what we actually use, and if we can remove some dependency that has some one feature we only use.
Overall, im amazed not more PHP devs look into Haxe as its basically a better version of what is TypeScript > JavaScript. Also there is no other compile to PHP language im aware of that ha the same robustness and features Haxe has.
But if you're looking for something more modern and interesting, then Hyperf looks pretty cool. They have a mini-framework version you can check out: https://github.com/hyperf/nano
It does require Swoole, but that is a lot easier to get your hands on these days
I find when I start a project I pretty quickly want to add an ORM, models, and maybe some middleware, and then I'm at a point where I might as well just use Laravel because it's fast enough and I know my way around.
IMO Laravel is kind of the spiritual successor to CodeIgniter, although of course a lot has changed between V1 and V11
e.g the market was wrong on graphQL.
btw Hono is cool, but found the api surface area insufficient for my node.js usecases.
I ask a a REST turned GraphQL advocate to be clear but criticisms I hear tend to be opinions or issues with specific implementations but not ones based on the technical shortcomings of the technology
None of that is inherent to the technology but it’s a common folly among developers. This is an issue with REST too but it can be more obfuscated
I prefer it over SOAP, but I think it's far too easy to ignore:
N+1 issues
Security (found that we had our entire schema open including internal data routes at my last job), also we had to refactor from patients being company -> patient to company -> pharmacy -> patient... that was fun
Overcomplicating resolvers
Not implementing pagination upfront
Dead end schema designs, since you need to plan much further ahead it really hurts when you mess it up. In REST you can make a V2 of a route and move on. Especially since many people ignore modules at first. Even large corporations get stuck with UserEntity_V2, updateUser_V2.
IMO if you are going "wow if only we had GraphQL" and your team only knows REST you are always better off improving your REST tooling and standards. For example, when adding a new entity/resource you can just plan to understand how your own teams intend to query for this data, rather than guessing with GraphQL or implementing every search pattern.
By your own admission it’s sloppy developer work that causes issues it’s not the tech.
REST APIs actually do have an inherent problem, which is they’re one call == one source. Everything has to be bespoke to the endpoint, where as GraphQL as a technology allows one to not have to do that.
Versioning APIs is a code smell. With GraphQL you can combine queries by using Fragments for example. You could also perform concurrent resolution with resolvers and merge data results if if it’s appropriate for the scenario to resolve a single query. There is far more flexibility in the model but you as a developer are 100% in charge of performance and such, no different than REST. GraphQL gives far more flexibility in finding a solution for any given scenario, where as REST is an extremely rigid 1 == 1 resource coupling.
As for pagination isn’t built into REST. Anything “standard” about that was bolted on and varies quite a lot. Where as GraphQL does address this[0] on an implementation reference level.
Regarding exposing schema, while I question if there is the security risk you're implying it to be (lots of organizations expose their GraphQL schemas, like Salesforce and GitHub) but never the less, any good implementation will have a single line option for turning it off. Apollo does (arguably the most popular of the implementations) but so does GraphQL Yoga and even implementations in other languages.
As far as developers go, the biggest mistake developers make is creating schema that is simply a clone of their database schema at the end of the day, and this is the absolute worst way to go about implementing GraphQL. Its explicit purpose is to have a middle layer that lets you express APIs for intended purpose, not to be coupled to your database schema
What I really liked from webdevt in Ruby was Rack. https://github.com/rack/rack (gosh I prefer the simplicity of the old logo)
And I found a Rack-like architecture in "http4k" https://www.http4k.org
In a way Kotlin can be looked at as a "typed Ruby". Sure Ruby now has optional types, but I believe it's not something easily bolted on later. The whole lang + stdlib should be built in an idiomatic way. Changing the language a lot later usually creates a mess in the stdlib.
The framework http4k delivers is very similar Hono/Dumbo, but it has a Rack built in as well. Also, http4k is make by functional programming enthusiasts. So it clearly separates logic and data.
Small request: Please make Hono clickable in the README!
But seriously, this has been a tool for me to relearn PHP, and those contributing so far have also been learning PHP. If it ends up just bein (and nothing more than) something helps me, as well as others learn more about PHP, it's a success.