If you work on all those projects alone, and you're happy doing this, you probably wouldn't. You aren't the target market for a framework like this.
Laravel (and any good framework, really) is for people who want a consistent dev experience _with good documentation_.
It makes sense that if Laravel is strongly-opinionated to result in a consistent dev experience, but is a consistently bloated dev experience better than an inconsistent lean one?
I don't know about this. But then I am of an age where I consider myself to be a team of programmers separated by time.
There are the younger, less easily tired versions of myself who thought this was a great idea for a career and lived on takeaway curries, there's me, and there are the four or five older versions of myself who will hate me for trying to be clever and not trying to be consistent.
Laravel helps me take on projects that allow me to hand off pieces of work among my team ;-)
Likewise, when a new developer arrives, they know exactly where to find everything because it has a place that it belongs, and they can reference the docs if they are having trouble.
It's less about the code and more about treating the project as a whole ecosystem.
Is something like this really harder to understand for a new developer than a Laravel project?
.htaccess
dbconfig.php
/api
/users
create.php
get.php
getAll.php
delete.php
/products
create.php
get.php
delete.php
And where each file does something like (simplified) // /api/users/getAll.php
include 'dbconfig.php';
checkPermissions(ROLE_ADMIN);
$res = $db->exec("SELECT * from users");
echo json_encode($res);Bad practice, as in security-wise, performance-wise, readability-wise, or something else?
If you trust the developer to implement things properly (use PDO prepared statements when storing data in DB, properly check for permissions, write efficient queries, etc.), shouldn't that automatically exclude common bad practices?
If the developer is inexperienced, can't they still implement something in a bad way in Laravel (e.g. save a user-submitted file on the disk without checking for permissions)?
That depends. How tired is the developer? How under pressure? How over deadline? ;-)
I do get your point and I understand where you're coming from.
But this model of PHP (where every URL entry point is its own script) is the thing that most encourages expedient development rather than good development, because you can just hack on that one thing without affecting anything else.
It also (traditionally) encourages somewhat riskier hosting configurations, because any PHP file the web server can route may need to be executable, and because a failure of web server configuration can expose PHP files as readable. Whereas with a single point of entry (index.php router), you can locate your codebase outside the document root, refuse to directly execute anything but your endpoint script, etc.
These are partly old-fashioned concerns, admittedly, but it's surprising how often the approach you're outlining is still the source of malicious PHP exploits where a script file gets buried in a hacked release, or where some server vulnerability can be inveigled into executing PHP code by some image file upload mechanism that didn't do adequate checking.
But at the same time, I have never seen a project built along the lines you discussed that has not collapsed under the pressure for expedience, and it's just as vulnerable to issues in libraries (which any project of any complexity will use).
Wikipedia, Facebook, Etsy and other huge platform are written in PHP, but I doubt they use a framework like Laravel and not some in-house built platform.
Very tiny projects probably need no framework.
That leaves medium-sized projects, but again, it's hard to define what "size" means. I think a project is bigger if it implements various functionalities instead of having hundreds of different files that do a similar thing.
I can see Laravel being used more by out-sourcing companies. Custom frameworks or no framework being used more by companies building their own product.
- Always use PDO prepared statements to avoid SQL injections
- Should probably implement a CSRF token check
- You shouldn't output values directly from the user/database and that can lead to XSS
attacks (either sanitize the stored data, or when outputting it make sure the page is always interpreted as plain text)
- You might forget to check for permissions in a specific route (code enforce this via some linting/IDE rules, by using some automated tests or by checking in an included shared script that permissions were indeed verified)Sanitize your data and use whatever driver you want. Prepare statements are like sending xml instead of json. If you are populating a database with known data why add the overhead?
Sure, this describes many Laravel and Symfony projects as well, and not every vanilla PHP project is bad. But there is definitely a pattern.
I would say, in this regard, that Laravel is better than plain PHP when working with inexperienced devs that are likely to make mistakes or write bad code.
The backend is completely separated from the frontend (so the PHP application just exposes an API to work with), so any code written there does exactly what you expect with no side effects on the client-side.
It's the almost that will get you here.
Does Laravel provide any protection in making sure you don't SELECT from the wrong table?
Is that harder to do than accidentally typing `SELECT name FROM flights` instead of `SELECT name FROM passengers`?
Aren't most of those issues found as soon as you first test the feature?
You can be protected from SQL injection and you can have various other query operations, and you can gain refactoring support (e.g. by telling the models the new table name), or you can add custom scopes that encapsulate transformations on the query.
Laravel also allows you to express model relationships, so Flight might have:
public function passengers(): BelongsTo {
return $this->hasMany(Passenger::class);
}
and then you can do things like: $flight->passengers->where('name', 'like', 'XCSme%');
> Aren't most of those issues found as soon as you first test the feature?I don't know.
The thing is, an ORM brings you other stuff (like a query builder integration) that allows you to construct queries without having to glue SQL strings together (and chain and pass query objects).
And Laravel separately also brings you a migration tool that allows you to encapsulate upgrades to your database as code snippets (so you can put code live without manually fiddling with SQL at all).
In my experience even really small apps benefit from this at some level. The discipline of using regular patterns like this is really useful.
(The Lighthouse GraphQL binding is where this stuff gets really interesting)
At any rate, we're unlikely to agree.
[edit: removed a tired-brain word choice mistake!]
Not good code, particularly, and not particularly good database design.
Also no documentation really.
But the implementation was pretty clearly pure Laravel, and the migrations ran without issue. So that was immediately a huge weight off my mind, because I knew I would be able to maintain the live, stage and dev boxes sanely.
The two biggest problems with this app were
1) the number of places they diverged from using the query builder for no really good reason when scopes could have made everything so much more readable
2) a false assumption they made about subquery ordering in MySQL (implicit ordering that worked for them in 4.x but would not work in 5.x, something along those lines anyway)
Because of 1), 2) was incredibly painful to fix. Dozens of bits of arbitrary SQL that could have been handled by the query builder.
And I'm sure the only reason it's like that is because that's the way they started out and they had time pressure that stopped them ever changing course.
Expedience kills software.
Unfortunately, this is how the majority of software is written nowadays. This is one of the reasons I prefer to build things slowly, think about stuff, implement them nicely, find clever solutions and optimize where it's possible. I know I could build more stuff and earn more money if I rushed things more, but I prefer building nicer stuff instead of more stuff. For most outsourcing companies, this doesn't really make economic sense though, but for product-driven companies it is still possible if the leadership decides to do it.
> the implementation was pretty clearly pure Laravel, and the migrations ran without issue
Being able to refactor/change one part of the code without being afraid that something else might break is an excellent reason to use a framework. Once you understand how that framework works, even if a codebase is bad, you can know what and how can break if not implemented properly. It increases the visibility of "code smells".
Yep. It's also more or less essential when something is subcontracted, like this was. In this case I think there were hard-working, competent developers who were burned by the original spec hiding a lot of undiscovered complexity, and what would have been a really good piece of work went inevitably quite wrong. The subcontractors clearly desperately tried to finish it within their parameters, and the result is something that met most of the spec but satisfied nobody.
(The framework decision they made wrong was in the front end, because there they made the disastrous choice to run with Angular 1.x -- which was presumably an in-house skill -- and not push to at least use 2.x. The resulting project is the precise kind of agony that Angular 1.x is famed for.)
The people that benefit from Laravel use a lot of its features and aren’t willing to waste time rewriting them for themselves.
In the businesses I have worked at, if we had spent the whole time building the stuff that Laravel already does for us then we’d have gone broke really quickly.
This is all said by someone who is working right now with a codebase with a checkPermissions function that they added to shift things off of direct $_SESSION access and which has since been almost entirely supplanted by route based authentication. I delight in working to modernize and secure legacy systems which is why I heavily favor Laminas over Laravel due to the add-it-as-you-need-it approach, when I first worked to convert our codebase to a framework we did it page by page and component by component with everything working fine for both legacy and framework fulfilled requests and we've slowly added more components as they've become necessary (and removed ones that are no longer of use).
I did switch the front-end side from no-framework (jQuery spaghetti) to a framework (React + MUI + TypeScript), but the main reason was that I needed:
1) Component reusability
2) Premade components (UI elements)
3) Data typing (thus TypeScript, to get autocompletion features)
On the back-end side, the default PHP language already supports most of those things, plus the reusability part is very little for an API (it's mostly having some basic functions such as auth/db connection and writing different queries), for which a framework wouldn't necessarily make things easier, just provide a different way of writing those queries (i.e. ORM vs direct DB query). I agree, it's nice that with an ORM you get autocompletion for the fields you want to select, but the databases that I usually use only have a few (intuitively named) columns, so if you take a look at the table it immediately makes sense (but the queries are still prone to typos, so you might get an error the first time you type it).
The biggest advantage we've seen though is in onboarding time. The more purpose driven and modular our code gets the quicker it is people pick up on each individual module types structure and new devs can start experimental coding quite quickly.
For me, personally, the ultimate attribute I value over everything else in a codebase is minimized maintenance costs - we have a few corners of our codebase that have extremely brittle automated tests that require hours of labour to execute the simplest of changes in and they're on our fix list. But the stuff we need to change frequently can be changed quickly and safely so our bug fix turn around is relatively minor. I'm actually in the middle of upgrading us from ZF2 to Laminas and this work is probably going to last about three weeks (with a bunch of the most annoying fixes coming out of Doctrine and their fanatical devotion to `final`ing every class under the sun - thanks guys) which honestly seems extremely reasonable to me for bumping two framework versions.
I'm also really not personally a fan of ORMs because the query building tends to make DB performance harder to tune and I loathe the performance implications of ActiveRecord approaches - but they're components I've built into our infrastructure to support other devs and I can comprehend their appeal.
Aren't frameworks harder to use in a long-term project if the codebase is not constantly updated to match the new framework standards?
For example, a code-base written in React (pre-hooks) is probably pretty hard to understand for a developer that has only learned React recently and uses hooks for everything.
Frameworks are heavier, but in the same way a company gets heavier as it gets more professional and more complex.
I think your use case doesn't require a framework, so don't think my angle is to convince you that you do. Just that there is definitely a time and place for them.
I write code to solve problems for my company, so building a framework is very low on my priorities. I'd rather just use something that is ready on day one.
Maybe it's not to everyone's taste but I like the fact I can just get on with trying to build my product.
Laravel is a sort of all-in option that tends to perform worst when integrated into a legacy project - it isn't completely overbearing (it won't creep into absolutely every file you're using) but it will end up requiring changes to a lot more files than is reasonable.
> I already know how to implement core functionalities when needed (e.g. CSRF, user permissions)
Even if you know "how", this is still wasted time on your part. These are solved problems.
Particularly when it comes to security features like CSRF, relying on yourself to implement it sounds like a major footgun opportunity. When you use a framework that has this built in, you have to try really hard to bypass these security features. You barely even have to think about how to implement it.
They work. If they are full of bugs they are a pain
They are complete. If they are missing parts because they weren't needed yet, they are a pain
They are documented. Documented well is a bonus
There isn't a self-made framework for every project at the company
The person who made the framework is still around
The person who made the framework didn't also make v2 and v3, mixing them in the same projectI think that if you need something a lot more complex than this (realtime communication, processing data in separate threads, linking microservices), then PHP is not a good choice.
I did have integration testing for a while for the core functionality, but in the end that was not helping much either, and after releasing a new version of the app I deleted the tests and (after 2 years) still haven't written new ones, without any bad consequences so far.
I deploy a new version to a beta branch, test it myself for a few hours/days (as I do use the app myself daily), then publish it live. Customers gradually upgrade to the new version and if anyone encounters an issue they let me know, and I fix it ASAP, but it almost never happens.
Also, the app is pretty complex, so writing tests for every use-case and environment is impossible.
I am not a big fan of writing tests when working in a small team (<5 developers). I did work on some pretty big projects that turned out great and very robust, without having written any tests.
That being said, if I ever have the time and am bored enough, I will write some integration tests, but mostly for the installation part of the application, not for the usage part.
No, you're just using the most expensive / error prone testing methods: doing it manually.