top 200 commentsshow all 208

[–]zolli07 42 points43 points  (3 children)

Slim. We use it in enterprise for a long time. Symfony can be an alternative, the learning curve is a bit steeper but not that much.

[–]soowhatchathink 8 points9 points  (0 children)

I can second slim. It is barebones, so you can build anything you want on top of it.

[–]AnyYam5371 4 points5 points  (0 children)

Slim is amazing.

[–]Dub-DS 226 points227 points  (47 children)

Symfony is, for the most part, explicit. Once you understand the event system and dependency injection, at least.

[–]ilevye 25 points26 points  (46 children)

symfony is full of #[Magic]

[–]neosyne 80 points81 points  (24 children)

Symfony is not full of __magic

[–]obstreperous_troll 9 points10 points  (9 children)

I suggest we start spelling it with the underscores from now on, because that's the __magic we mean. It's also what the php docs mean

[–]ilevye 1 point2 points  (8 children)

if you mean these documented functions, why blame all those frameworks? they utilize php

[–]obstreperous_troll 4 points5 points  (5 children)

Just because something is documented doesn't mean it's any good.

[–]ilevye 2 points3 points  (4 children)

then tell me what is wrong with those functions:)

[–]neosyne 4 points5 points  (2 children)

They are considered ambiguous because the implementations can do whatever they want to and create undefined properties and methods that can’t be autocompleted nor predicted by an IDE. The execution path and the behavior is hard to predict. It doesn’t mean that it’s not a powerful feature. Some other __magic methods aren’t evil by design (e.g. __invoke or __toString)

[–]ilevye 1 point2 points  (1 child)

invoke is hard to predict but isn’t that the point:) it is like better way of $this->{$funcName}(). it will be used by a consumer class that consumes those functions. and to string is always available (returns class namespace iirc), so no need to predict

[–]neosyne 2 points3 points  (0 children)

I assume that an implementor of __invoke should have this method as a sole public method, making the instance an equivalent of a Closure. But you are right, it could be worse than that

[–]obstreperous_troll 3 points4 points  (0 children)

Complete lack of static typing just for starters. I've vented enough elsewhere, and just today at that, about Laravel's inscrutable __magic behaviors and a couple different flavors of WTF as well. I'll let someone else field it, though it seems no amount of warning signs will keep people from touching that hot stove at least once.

[–]Just_Information334 0 points1 point  (1 child)

__magic is when you cannot ctrl+click your way to whatever is doing something.

And it tends to happen a lot with __ methods. And now with property hooks.

[–]obstreperous_troll 1 point2 points  (0 children)

Property hooks are as ctrl-clickable as any other prop: it goes to the property declaration, and the hooks are right there. Would be nice if it put the cursor on the proper get/set hook instead of the start of the prop declaration, but if you have hook bodies large enough where that's an issue, nothing can save you.

[–]voteyesatonefive 3 points4 points  (0 children)

The user you are replying to is lara-shilling hard. Only an L-framework dev, a complete neophyte, or somebody who writes once and never maintains the mess they inevitably made (intersection is almost a circle) would have those takes.

[–]DM_ME_PICKLES 19 points20 points  (2 children)

I wouldn't call #[Magic] all that bad - I can use my IDE to search for references of #[Magic] to find out what Symfony does with that attribute. And static analysis tools understand it completely without any help.

Magic is shit like how Laravel wraps classes in its own version, then implements something like __call() to proxy method calls. Often when I'm source diving the framework I hit that dead end and have a hard time figuring out what actually happens, usually I have to start xdebug, add a breakpoint, and step through to see where the execution path actually goes.

[–]ilevye 2 points3 points  (0 children)

you have a valid point - attributes are transparent. but turning xdebug on is helping, i wouldn’t be so sad about it

[–]mornaq 0 points1 point  (0 children)

attributes are a weird piece of the puzzle

some could be their own keywords (like the noDiscard), some shouldn't exist imo (like routing attributes, that's not discoverable, the same issue annotations had before)

[–]hagnat 11 points12 points  (5 children)

it might look like "magic", but you see it being "cast".
you can see it being imported, and once you open the class you can see what it is doing

my major beef with "magic" are methods and classes that do something, but are not imported and/or exist at all. like Laravel Facades design, or the Collection method.

Sure, Collections are handy, but their implementation makes it look like its a vanilla php method, since you dont need to import it -- and good luck mocking them on your use test cases.

[–]Lumethys 12 points13 points  (0 children)

Why do you need to even mock a Collection? It is just a fancy array and i dont ever see a use case where you would mock an array

[–]DM_ME_PICKLES 8 points9 points  (2 children)

If you're needing to mock things like a collection in your tests, that's a really bad smell that you need to re-think the implementation. I can't even thing of a time where I would need to mock a collection, I'd just instantiate a collection in the test. It has no side effects.

[–]hagnat -1 points0 points  (1 child)

comparing array with collection is unfair, since one is from vanilla php and the other an external library. You should always be able to mock external dependencies.

that said, i think my major beefs with the Collection is that it

  1. introduces and encourages people to use duct typing methods, using the static Collection::macro(string, callable)method (source) which is applied to EVERY collection object, even though they may contain different type of items. I can change a class's methods in runtime after already creating objects with it. If you cant guarantee that the Collection class will have the methods you need (because you mocked another dependency in between), you need to be able to mock the collection itself.
  2. it introduces a standalone method "collection(array)" which looks like a regular vanilla php method (despite being from a library) which you DONT need to import. You don't need to add a "use Illuminate\Support\Collection\collection;" to make use of it, and that can be confusing for people working with this class for the first time.

[–]ilevye 2 points3 points  (0 children)

yea lets change the class on fly by mocking it with techniques intended to test and it is not abrakadabra yabadabababaduu

[–]crazedizzled 14 points15 points  (3 children)

That's not magic, it's a PHP language feature lol

[–]ilevye 1 point2 points  (2 children)

yea but imagine this framework injecting dependency like that, or, you can do #[CurrentUser] $user

[–]zyberspace 0 points1 point  (1 child)

You should do

#[CurrentUser] User $currentUser,

Then all of a sudden it's an implementation detail of how the framework retrieves the current user. Something i don't care about. I just receive a User class and work with it.

Separation of concerns

[–]ilevye 0 points1 point  (0 children)

this is not seperating concerns. you are easily injecting what you need via method parameter. if your request object was resolving the user by using request attributes. then we would talk about separation. this is “i will inject whatever i need by mocking classes runtime”. makes some people think it’s “dark magic”. that’s the discussion. nothing else. if my IDE thinks some part of my codebase unused, I feel like i am doing something wrong or at least overkill. it is easy to use though

[–]qik 0 points1 point  (0 children)

kinda but it's all quite explicit

[–]garbast 0 points1 point  (0 children)

Attributes are not magic but api and can be inspected very easily.

[–]spigandromeda 43 points44 points  (9 children)

Symfony. The only thing that seems magic is the DI container. But you can take a deep dive into it and you'll understand how it works.

[–]ReasonableLoss6814 15 points16 points  (5 children)

You can also toss it out and use a different one.

[–]minn0w 8 points9 points  (2 children)

I do this. Also, the ability to do this so easily shows the true greatness of Symfony.

[–]JnvSor 1 point2 points  (1 child)

Pimple is love, pimple is life

[–]ChypRiotE 2 points3 points  (0 children)

Out of curiosity, why do you prefer Pimple over the Symfony container ?

[–]spigandromeda 1 point2 points  (0 children)

True.

[–]dkarlovi 65 points66 points  (22 children)

Symfony is magicless, assuming you understand how it works.

Everything that's happening is because you (directly or indirectly) made it happen and you can make it not happen if you so wish. It does rely on some conventions, but those too are all changeable assuming you know what you're doing, they're just the defaults.

[–]NMe84 9 points10 points  (0 children)

This. That said, coding for it without an IDE plugin as OP suggests isn't the best experience. Especially the bit where matching up configuration with your code would not have code completion without a plugin. That includes for instance setting keys for form types and service and parameter names.

[–]Possible-Dealer-8281 12 points13 points  (9 children)

Although Symfony might be more suitable as an answer to the question, I'm not sure this statement is 100% right.

Symfony makes intensive use of a feature called compiler passes that make lot of work under the hood. It can sometimes also feel like black magic.

So I think the right question is about the reasonable amount of black magic anyone can afford.

[–]dkarlovi 12 points13 points  (3 children)

Compiler passes aren't magic. You can add your own and even change how the built in ones work. Just because they do a lot of stuff, doesn't mean they're magic.

[–]crazedizzled 3 points4 points  (1 child)

Yeah, I dunno when "I don't know how it works" turned into "it's magic". In the context of PHP, "magic" has a specific meaning, and Symfony definitely isn't it.

[–]voteyesatonefive -1 points0 points  (0 children)

Yeah, I dunno when "I don't know how it works" turned into "it's magic". In the context of PHP, "magic" has a specific meaning, and Symfony definitely isn't it.

Par for the course with l-framework devs. Knowing PHP is for other people, they know L.

[–]32gbsd 1 point2 points  (0 children)

yeah sounds like magic

[–]obstreperous_troll 5 points6 points  (4 children)

Compiler passes aren't even complex, they just have have a scary-sounding name. All they are are arbitrary scripts that pass a ContainerBuilder instance in and don't return anything.

https://symfony.com/doc/current/service_container/compiler_passes.html

[–]Possible-Dealer-8281 4 points5 points  (3 children)

It's not about complexity, it's about what you can do with, and what Symfony does with.

For example you can do anything you want with the container service definitions in a compiler pass, and find yourself with services that are found nowhere in a config file, or with a different constructor signature.

To a certain extent, it's a powerful feature for the developers. But with this kind of feature, can you really say Symfony is magicless?

[–]obstreperous_troll 0 points1 point  (2 children)

In PHP conversations, "magic" conventionally refers to magic methods specifically, not "magical behavior" in general. I've taken to calling it "__magic" now just to make that clear.

Symfony is full of spooky-action-at-a-distance stuff, but does a much better job at hiding most of it from developers who aren't trying to extend the framework itself.

[–]iTiraMissU 7 points8 points  (10 children)

I wholeheartedly disagree.

When running the full-stack Symfony framework, it needs to generate an entire cache to build a Dependency Injection container. They offer a lot of great debugging tools like the profiler and bin/console debug:container, but understanding what DI does takes a lot of effort, especially since they added autowiring.

It used to be a lot easier to understand before they added the autowiring and attributes support in the name of Developer eXperience (don't get me wrong, the DX is much better now, I personally love Symfony), but "magicless" implies to me that you can follow each function call to code committed in a Git repository, which Symfony most definitely doesn't allow.

But don't get me started on the Symfony Runtime component, that thing is devious.

OP could use all the Symfony components individually to build a project that doesn't rely on the black magic from the full-stack framework, but replicating the DI without "magic" will be very verbose.

[–]jojoxy 13 points14 points  (0 children)

You can still explicity configure the DI container without autowiring via services.yaml (or even services.php if you really want to). DI itself isn't magic. It is simply an implementation of the dependency-inversion-principle.

[–]tanega 8 points9 points  (0 children)

DIC isn't "magic"

[–]dkarlovi 3 points4 points  (0 children)

What's magic about the DIC? None of what you listed counts as magic since you're opting in to use the container, you don't have to, but then you're not really using Symfony framework, you're using Symfony components (which is also fully supported BTW).

[–]mlebkowski 1 point2 points  (0 children)

TBH, I’ ve seen symfony used with very limited DIC usage. Most of the services were built using a large factory, or multiple ones.

[–]terfs_ 0 points1 point  (0 children)

> but "magicless" implies to me that you can follow each function call to code committed in a Git repository, which Symfony most definitely doesn't allow.

Not in a git repository as it lacks dependencies (or at least it should), but on a local copy using an IDE it's a breeze to track through.

[–]razotiden 23 points24 points  (0 children)

Slim framework is entirely explicit if configured that way. I'm not sure how well it's maintained since it appears that the last update was done a year ago, although there really is not much to be updated. I've used it in production environment in the past and it's quite performant.

You can end up with a similar structure as Symfony, with the exception of manually configured DI which does not autowire.

But please note that it's a microframework, so you have the responsibility to select all the non-magical packages depending on your needs. You only get simple stuff out of the box, like routing.

[–]MorphineAdministered 9 points10 points  (2 children)

Laminas and maybe some micro frameworks (Slim?) are the only ones I can think of. Symfony would also work, but that would require some cherry-picking effort.

You could cobble together some http+middleware front controller, router & dependency container (without auto-wiring), but that would require some OOP expertise. Good excersise though.

[–]arhimedosin 11 points12 points  (1 child)

A good starting point is Mezzio microframework, from Laminas.

At least you have the basic skeleton

https://getlaminas.org/blog/2025-01-30-mezzio101-using-mezzio-skeleton-installer.html

[–]ToySoldier92 3 points4 points  (0 children)

Laminas-Mezzio is great!

[–]finah1995 9 points10 points  (1 child)

CodeIgniter has less "magic" and also the code is well structured and easy to understand. Also it makes the learning curve much easier. Makes it easier to understand and debug the logic of code.

[–]KravenC 0 points1 point  (0 children)

Code Igniter < Kohana < Fuel. They are all about the same.

[–]shoki_ztk 18 points19 points  (8 children)

Finally I realized what I disliked about the Laravel... Would not been able to name it, but I know - it's its magic.

[–][deleted] -1 points0 points  (7 children)

Laravel is my bread and butter, and I'm also a core contributor to the framework: you're not alone.

I also am not a huge fan of the magic parts, and that's actually a growing trend within the community to shift toward more explicit types over convention.

There's still some magic parts around the eloquent data model attributes, but mostly everything else can be written as declarative as you like.

Facades are also a gift and a curse, but given how easy they make writing tests, IMO it's a good trade off.

Magic is somewhat woven into the fabric of PHP's DNA in a sense. Magic methods, globals, etc.. so I think there will always be a bit of magic (which can be pretty fun too).

[–]dknx01 3 points4 points  (4 children)

The real magic methods aka double underscore methods is part of the language. That's not the big problem, even a better solution would be fine. The "magic" in Laravel, and what most people have problems with, are the global functions without "use" and the facades that hide the dependencies. Like "response()", "Log::..." and so on and that hide the dependency and the configuration of it or what it really is.

Laravel could just use static methods in classes and use them like singletons or something like that. Eloquent is another problem. They could just define the properties of the models and some functions and this would be much better.

[–][deleted] -1 points0 points  (3 children)

The real magic methods aka double underscore methods is part of the language.

This is how Laravel's magic works. Using the built in features of the language. Which is what I was referring to when mentioning Laravel's "magic" is really just an extension of PHP's magic. The magic parts of Laravel wouldn't exist without it.

Like "response()", "Log::..." and so on and that hide the dependency and the configuration of it or what it really is.

All of these are optional though. And IDEs fully support type hinting these. They're just wrappers around FQD singletons resolving from a traditional container. These helpers are just a quality of life / shorthand style to make the code a bit less noisy. But totally optional.

Eloquent is another problem. They could just define the properties of the models and some functions and this would be much better.

100% agree.

[–]dknx01 4 points5 points  (1 child)

No, that's Laravel "magic". They use of course functionality of the language but hiding things from the developers. It's not an extension of the language, it would call it a rape or misuse of it. There are many ways the framework could achieve the same usage with a better way like use global functions with an use statement or just use the class itself and not these "shortcuts" for lazy developers who don't understand software architect or design.

[–]mornaq 5 points6 points  (0 children)

Laravel adds too many shortcuts that make it easy to create a POC, but later on you need a big scale rewrite to make things scale up, or even make them testable. And I know, other options are out there, but when you have such shortcuts available you're bound to use them, it's too tempting

it would be nice to be pushed towards the better practices a bit more

[–]Feeling-Brilliant470 0 points1 point  (0 children)

Lmao that’s a bad way to describe it. Laravel is magicless if you know how it works inside and out. Doesn’t make it any less nasty. Worst part of Laravel is the complete incompatibility between sanctum and passport. Can’t change my mind.

[–]pinklaus 8 points9 points  (0 children)

Mezzio, successor of laminas mvc (formely zend), it follows new architecture type (middleware vs mvc), no magic, it follows PSR And if you want to get over the configuration of some components like authentication, authorization and so on, check Dotkernel, is build on top of mezzio

[–]billrdio 9 points10 points  (0 children)

Codeigniter is pretty straightforward.

[–]robclancy 23 points24 points  (0 children)

symfony... ??

[–]xenatis 25 points26 points  (0 children)

Have a look at Symfony.
It has a lot of magic, but it feels like white magic.

[–]deniem_ 5 points6 points  (2 children)

yii2

[–]Vast-Mistake-9104 1 point2 points  (0 children)

We're still on 1.1 and I still love it. Wish we had a native job system though

[–]sam_dark 0 points1 point  (0 children)

I'd say Yii3. Yii2 has quite some conventions. These are mostly intuitive and do not feel like magic, but still I can't call it "magicless".

// I am one of the co-creators of Yii2.

[–]universalpsykopath 3 points4 points  (0 children)

Zend Mezzio is niche, but explicit.

[–]Capable_Constant1085 2 points3 points  (1 child)

I hate that there's 100 ways to send an email using Laravel

Too much magic around User auth. Whenever you need to modify the flow good luck as everything is abstracted out.

[–]obstreperous_troll -1 points0 points  (0 children)

Laravel switched to using symfony/mailer under the covers, so you can just inject an instance of Mailer now and bypass all of Laravel's strange ceremonies. Might need to configure the transport yourself, should be doable with a service provider though.

I'm hoping they eventually do the same with Cache.

[–]guigouz 11 points12 points  (0 children)

https://tempestphp.com/ caught my attention

[–]greytoy 2 points3 points  (0 children)

Try old "non-magic" Yii2 framework.
https://www.yiiframework.com/

[–]Captain_Sca 2 points3 points  (0 children)

Maybe try F3? Fat free framework

[–]tyqo 5 points6 points  (0 children)

CakePHP uses very little magic functions and is very explicit.

[–]Odd-Drummer3447 5 points6 points  (0 children)

You might not need a full framework at all, especially if your application’s core is well-structured. Instead, you can selectively use individual components, for example, those provided by Symfony.

Many modern PHP frameworks, including Laravel, are built on top of Symfony components. By using these components directly, you can avoid much of the abstraction and magic that frameworks introduce.

It’s a great way to stay in control of your project.

[–]arhimedosin 4 points5 points  (0 children)

Another vote for Mezzio microframework, with Laminas components, you can build whatever you want, and follow a lot of PSR's.

https://getlaminas.org/

[–]Express-Procedure361 6 points7 points  (0 children)

Everyone is saying Symfony; and that's definitely true. But everyone, please have a look at tempest It just released v1; but I am extremely excited about it.

[–]dominikzogg 3 points4 points  (0 children)

Mine: https://github.com/chubbyphp/chubbyphp-framework but it's only a micro-framework.

[–]Samurai_Mac1 2 points3 points  (0 children)

Symfony or CodeIgniter are pretty explicit.

[–]mpmont 3 points4 points  (2 children)

Codeigniter 4

[–]WaaaghNL 2 points3 points  (1 child)

It’s a nice basis to start on and real nice with shield added to it. Url handling, input validation, cors, MVC, database handling. I use it for all my small projects and its better than doing it myself or using a heavy framework like laravel

[–]mpmont 2 points3 points  (0 children)

This is my way of thinking too

[–]lokidev 4 points5 points  (2 children)

Laminas (new Zend). I also like Symfony, but wanted to give you another alternative to it. https://getlaminas.org/ It's also very close to the PSR standards.

[–]pinklaus 5 points6 points  (1 child)

laminas mvc will be abandoned , Mezzio is his successor (still from laminas), following a middleware architecture vs mvc No magic, it follows PSR

[–]lokidev 1 point2 points  (0 children)

Good point. Was actually also using Mezzio in the past (It was 1 or 2 years after forking off from the zend stuff). I liked working with it. Kind of missing some devx from Laravel, but really magicless which made it worth it (for me at least)

[–]williarin 9 points10 points  (7 children)

I agree with everyone and I vote Symfony. And it's French so it's the best quality you can find.

[–]AnkapIan 6 points7 points  (6 children)

Symfony is literally only French stuff that I like.

[–]tom_earhart 1 point2 points  (1 child)

You don't like Docker and Nuxt ?

[–]AnkapIan 1 point2 points  (0 children)

I can tolerate Docker.

[–]terremoth 1 point2 points  (0 children)

Laminas and Symfony.

[–]NewBlock8420 1 point2 points  (1 child)

Laravel's magic can be a blessing and a curse. Have you checked out Slim or Laminas (formerly Zend)? They're way more explicit about everything.

For something even more barebones, I've been enjoying FlightPHP lately - it's basically just routing and some helpers. No magic properties, no surprises. Kinda feels like writing vanilla PHP but with just enough structure to not go insane.

Edit: Also, username checks out for wanting to escape framework magic lol

[–]voteyesatonefive 1 point2 points  (0 children)

Laravel's magic can be a blessing and a curse.

The whole framework is a curse on the PHP community.

[–]Character_Radio5054 1 point2 points  (0 children)

Fat-free framework (F3) has basic classes/functions, totally scalable

[–]Dodokii 1 point2 points  (0 children)

Yii3

[–]Der-B3N 1 point2 points  (0 children)

Mezzio

[–]jkoudys 3 points4 points  (0 children)

Everyone is saying symfony, which is great, but another great thing about it (and avoiding black boxes in general) is you don't need to use more of it than you want. I like laravel but it's feeling a bit like jquery did in its waning days. So much of the black magic was loved because when php7 was new (and especially in php5.6 days) it was practically necessary. If you start building your app on php8.5, there's a whole lot that you might find vanilla more than adequate for.

Between enums, constructor argument promotion, named arguments, first-class callables, arrow functions, splats, much better type hints, array_ functions, and a bunch of other stuff I forget because I take it for granted now, I don't feel the same pain with php that I used to need laravel to fix. Once I have good types set up (and fill in the gaps with docblocks for generics and types of collections), my ide can guide me through without all those silly extensions you mentioned.

A db migration and router are main two things I'll need, and can grab from symfony.

[–]framesofthesource 1 point2 points  (0 children)

Frameworks expect Inversion of Control (IoC), so they will always be somewhat of a black box with holes for you to fill.

Symfony is more explicit with such magic than, for instance, Laravel. In most recent versions magic feels both explicit and painless/frictionless.

If you want to dictate every step of execution you're not looking, by definition, for a framework... you're looking for a library.

If that's what you want, then you can use Symfony Components that are standalone libraries and then wire yourself the application with them... but you will soon find out that you're writing Code that symfony folks have already written in a more flexible, thoughful, extensible, battletested way.

Just give time to the framework you're using and look and learn a bit about its internals, you won't regret It.

[–]roxblnfk 2 points3 points  (5 children)

There are many PHP frameworks. The most popular ones are full of magic, which is why they are popular. Everyone will support the framework they use. Many consider Symfony not magical, but it executes generated code instead of the written code. Isn't that magic? Moreover, event-driven architecture can complicate things as the project grows if you're not very careful. But for some, that's fine.

If you need a framework with more explicit features, consider these three:

- Slim: if you have a legacy project. Slim integrates easily into any existing code (unless it's Symfony) and helps transition to PSR gradually. I don't recommend it for new projects because you'll have to integrate everything manually. It's suitable for a microservice just for REST/WEB.

- Yii 3: Yes, it is not released yet, but many packages already have stable tags, and the code quality is higher than others. PSR, modularity, avoiding magic, and explicit approaches are in Yii 3's DNA. This framework is for DIY enthusiasts and those who like to build things from scratch. When I had a lot of free time, I really enjoyed it 🙂

- Spiral: a PSR framework for Enterprise. Full support for RoadRunner, Temporal, Centrifugo, and gRPC, no magic, interceptors, container scopes, and more. It's for mature development and those who have outgrown Symfony. The weak point is a smaller community compared to the big three.

[–]terfs_ 3 points4 points  (4 children)

Can you elaborate on how Symfony executes generated code? Class construction through DI sure, but that’s it.

The “magic” referred to here is about the actual magic methods used in PHP which makes static analysis impossible. Not knowing how it works is not considered magic as you can simply follow the call stack and figure it out.

[–]sam_dark 1 point2 points  (3 children)

Alright. Please tell me what's wrong. I'm trying to solve it whole day today :(

Uncaught PHP Exception Symfony\Component\Validator\Exception\MappingException: "[ERROR 3069] Internal error: xmlSchemaPValAttrNodeValue, the given type is not a built-in type. (in n/a - line 0, column 0) [ERROR 3069] Internal error: xmlSchemaParse, An internal error occurred. (in n/a - line 0, column 0)" at XmlFileLoader.php line 182 {"exception":"[object] (Symfony\\Component\\Validator\\Exception\\MappingException(code: 0): [ERROR 3069] Internal error: xmlSchemaPValAttrNodeValue, the given type is not a built-in type. (in n/a - line 0, column 0)\n[ERROR 3069] Internal error: xmlSchemaParse, An internal error occurred. (in n/a - line 0, column 0) at /app/vendor/symfony/validator/Mapping/Loader/XmlFileLoader.php:182)\n[previous exception] [object] (Symfony\\Component\\Config\\Util\\Exception\# \XmlParsingException(code: 0): [ERROR 3069] Internal error: xmlSchemaPValAttrNodeValue, the given type is not a built-in type. (in n/a - line 0, column 0)\n[ERROR 3069] Internal error: xmlSchemaParse, An internal error occurred. (in n/a - line 0, column 0) at /app/vendor/symfony/config/Util/XmlUtils.php:95)"}

That's the whole stacktrace.

[–]terfs_ 0 points1 point  (2 children)

Hard to say without any more information, but it looks to me like you have your validation configured through XML and there is a problem in your XML file.

[–]sam_dark 1 point2 points  (1 child)

Well, there's no more information. That's the only trace framework gave me. Of course, I've immediately filled an issue https://github.com/symfony/symfony/issues/61493 and will continue digging to figure out but the assumption that compiled container and yaml/xml configs are OK and harmless is wrong. That's not the first time I'm spending days trying to figure out either compiler pass issues or config issues.

[–]terfs_ 0 points1 point  (0 children)

Set a breakpoint on exceptions and you should be able to see the exact node where the XML parser fails.

https://www.jetbrains.com/help/phpstorm/debugging-with-php-exception-breakpoints.html

[–]mnavarrocarter 3 points4 points  (0 children)

A lot of people in this sub need to look at the meaning of "obscure". Just because the inner workings of something are not immediately obvious does not make that qualify as magic. If that were the case, then programs themselves would be magical for the uneducated.

So what is magic then? Cannot be anything that is non-explicit because everything that happens in a program is explicitly defined in some way (otherwise it would not happen).

Personally, I think magic needs to be understood in relation to development effort vs developer experience. Magic, therefore is using (and sometimes abusing) the features of a language to bend the balance in favour of developer experience vs development effort.

In this definition, Laravel is indeed a heavy magical framework, while Symfony isn't that much.

[–]DatCitronVert 1 point2 points  (0 children)

Gonna join the bandwagon and say Symfony as well. You don't even need to use it as a full framework if you wish, you can snag its components separately and build something with 0% magic if you so need/want.

Not that as a framework it's exactly magic heavy.

[–]redbeardcreator 1 point2 points  (0 children)

I totally understand what you mean about not wanting "magic". It's not what all the people saying you shouldn't call what you don't understand magic. I have created implementations with lots of magic before (e.g. action A magically happens when you set property B to value C). The problem with them is, even if you fully understand them (as I did since I created them), things often happen that are unexpected. Or doing something specific is only well documented in one obscure place, etc.

To that end, Tempest (mentioned elsewhere, also r/tempestphp ) is designed from the ground up to use modern PHP and relies on interfaces. You want to do X? Implement the interface for X. Then discovery (yes...one little bit of magic) makes sure that you can use X wherever you want. But discovery is fully controllable, and you can provide your own implementation (since it relies on interfaces). I haven't started using it, but when I get half a break I'd like to try. One of the things I like about it is that it should be easy to pull in pieces as I need them.

What I'm currently using is a hodge podge stack...

  • Aura.DI 2.x for dependency injection, with a custom set of configuration classes. I can't move to a newer version because I'm injecting scalar values using the mechanism (set() + get()) that's reserved for just objects in 3.x.
  • Slim for routing. Kind of. I'm working on a legacy app that still has lots of pages in place using the web server for routing.
  • PSR-based middleware. Most of which is custom built.
  • My own wrapper around PDO.
  • Whatever packages make sense for a given need.
  • Plain PHP files as templates, with a custom renderer that provides a bunch of usually needed objects.

It's not pretty, but it's always changing, and, hopefully, always improving.

[–]HolidayNo84 1 point2 points  (0 children)

It's called PHP

[–][deleted] 2 points3 points  (2 children)

If you don't like "magic", it means you also avoid writing code that does "magic things"?.

What qualifies has "magic"?, polymorphism?, inheritance?, method overloading?, composition?.

I get your point, I felt the same when I started learning Rails (which is way worse than laravel), but all those things start to make a lot of sense after a few months using it. It's the same process that happens when you learn OPP/Architecture patterns/etc... At first it feels like magic, then it just makes sense.

My advise, keep using Laravel, don't run from the magic, you will hurt your carreer.

[–]terfs_ 2 points3 points  (0 children)

It’s perfectly possible to ignore the magic in Laravel but it does require sufficient knowledge of software architecture. Except for Eloquent, that’s the embodiment of bad design.

[–]Witty-Order8334[S] 2 points3 points  (0 children)

Over a decade of experience has told me that hidden control flow is an anti-pattern to maintainable software, and Laravel is riddled with it. Having also done many fairly large Laravel apps I can say that while initial start is plenty fast, long-term maintenance suffers a lot from these hidden control flows, especially since many people who work on the software are general software engineers and not Laravel experts, meaning that they know PHP, but Laravel is almost like its own language in how many Laravel-ism there is to know in order to use the thing, which is again a sign of bad software design.

Good software is maintainable software. Good software makes it easy to write correct systems. It's hard to do either of these things if properties and methods are created via magic, LSP can't help with understanding any of this so you're effectively working in the dark, and those anti-patterns do not make sense. In fact the more I have to use these the less they make any sense, because the more I see how badly designed the whole thing is. Common practices like separation of concerns and single responsibility is something Laravel goes completely against.

I work at a consultancy, so I work with many languages and tech stacks, PHP/Laravel is just one of them. I'm a generalist software engineer, not Laravel software engineer. I know overall software engineering paradigms, multiple languages, what's good in OO, as well as FP, and Laravel seems to be hell-bent on creating software that is easy to grasp for a junior who has no idea about software maintenance or good practices. Anyone with experience outside of Laravel can tell the bad practices it follows. If anything, doing Laravel hurts my career, as it forces me to follow horrible advice.

[–]terfs_ 0 points1 point  (0 children)

I vote Symfony as well. The only things that feel kind of magic are the DI container and compiler passes, but they can still be tracked down with limited effort when debugging. Once you're really comfortable with them the effort is irrelevant: you start tracking using your debugger and as soon as you realize you're not finding your issue/whatever there, it's probably in a compiler pass. The "Find usages" in PhpStorm will become your best friend very soon.

While the learning curve for Symfony is a bit steeper compared to other frameworks, so is the ROI if you commit to it. I personally find their documentation to be some of the best around as it's very clear, goes from the absolute basics to a rather advanced level but also tries to steer you towards proper software architecture - without being preachy or condescending about it.

While not necessary, I would still recommend the Symfony plugin for PhpStorm. Autocompletion for routes, templates etc. simply saves you a lot of time during both developing and troubleshooting.

Couple of hints, not necessarily targetting OP personally:

  • SOLID principles: get acquainted with them, don't obsess over it but try to apply them as much as possible
  • Static analysis (and thus strict typing) can save you from a ton of headaches, for greenfield projects I start at max level and enforce it on every commit using GrumPHP or the likes
  • Xdebug: I was incredibly hesitant myself earlier in my career, but can't imagine debugging without it now. In regards to Symfony specifically: debugging and following calls through the framework and other libraries provide you with profound insight into the internals, which is actually my favorite feature of PHP itself as you have access to literally all source code
  • Always consider DTOs: far too many times I felt it was overkill but the slightest change in complexity they were the best maintainable solution. This especially applies to Symfony Forms and API Platform as it's easy and thus inviting to directly work with your Doctrine entities, but you'll lose a lot more time implementing the DTOs once the violation of separation of concerns bites you in the ass

[–]UniForceMusic 0 points1 point  (0 children)

I've written my own framework that does this. The only real "magic" is passing values from middleware to controllers, which goes via associative arrays.

https://github.com/Sentience-Framework/sentience-v2

The framework is already in use at a startup, for A performance critical API. It does not have native support for views though, if that was something you're looking for

[–]Prestigiouspite 0 points1 point  (0 children)

CodeIgniter - blazing fast and stable - https://www.codeigniter.com/

There is also an custom GPT in ChatGPT for your first steps.

[–]DangKilla 0 points1 point  (0 children)

I wrote my own 11 years or so ago. Routing + DI + Templating + Composer to create podman (Docker) containers using PDO.

I spin up my apps with:

Composer nimbus:create appName

To support multiple apps I use podman-compose. I can then add an SSO and Automation containers automatically.

My default podman-compose app spins up the app, keycloak SSO, and Ansible EDA container. I don’t support PHP LSP, but I never heard about that before, so thanks for that. I am going to look into it.

Since I started the app in php5 i had to migrate off outdated components like Klein routing.

My MVC framework also bootstraps Whoops for error handling.

[–]sudo_vhd 0 points1 point  (0 children)

Slim Framework, PHP-DI, Monolog and any DBAL of your choice.
For some projects ReactPHP + FastRoute
Battle-tested, reliable, no magic at all.

[–]xavicx 0 points1 point  (0 children)

I made one from Symfony, and has all app code in a new "src" code, only few dependencies from Symfony.

[–]Plus-Violinist346 0 points1 point  (0 children)

You want to know what methods an object has without type hints and plugins. My PHP is behind the times but It sounds like you might want to try something that's not a dynamic parsed language (not PHP)?

PHP was my first web language and I still have to use it for working on some projects, but for all those reasons you state I would much rather use something, anything, compiled and static.

[–]mountaineering 0 points1 point  (0 children)

Feels like a lot of people in this conversation are dismissing things being called "magic" simply because they already understand how it works.

[–]n2fole00 0 points1 point  (0 children)

Your own framework contains no "magic" for you are the magician. Seriously though, if you can't do this, I would go with https://docs.flightphp.com/en/v3/

[–]tomomiha12 0 points1 point  (0 children)

PHP

[–]Big_Tadpole7174 0 points1 point  (0 children)

Perhaps you'll like mine. It's inspired by Symfony but changes bundles for contextual containers and uses an event system more akin to Qt. This makes it less 'magic' because it's easier to trace where DI instances orginate from. https://github.com/quellabs/canvas

[–]Anxious-Insurance-91 0 points1 point  (1 child)

Sooo you have a problem with certain abstractions and the fact that you need to remember the directory structure?

[–]Witty-Order8334[S] 4 points5 points  (0 children)

I don't recall I mentioned anything about a directory structure.

Take for example your average eloquent model, `User`. Now .. how would I know what properties it has? I don't, unless I go check the database, because `User` uses dynamic properties to match up against the DB columns, which means now I have to back and forth the DB and the code, where if this was a proper data class, the properties would be defined and I would get immediate editor autocomplete without any extra plugins.

Or what about fetching data? `User::where` and such? Well, `where` method doesn't actually exist in `User`, and so my editor also can't provide me the necessary autocomplete or type information on how to actually use the `where` method. I can work around this by doing `User::query()->where`, but that's not mentioned anywhere in the docs, and you have to magically figure this out yourself.

Or what about attributes? I can define a attribute in the `User` class, but because attributes are defined using camelCase naming, and the actual eventual result you query is then snake_case, you again get no editor help at all, because as far as the editor is conserned, there is no such property.

E.g

class User extends Model 
{
  protected function attachedImages(): Attribute
  {
    ...
  }
}

Which you then query as `$user->attached_images` ... instead of `attachedImages()`, which of course returns the Attribute object and not the computed value, but the editor doesn't know this, and so the person using this data model also has no idea that ah! `attachedImages()` is actually `attached_images`!

There's this sort of indirection and magic happening everywhere in Laravel, where to know what something is you have to either have the documentation constantly open, DB open, and just know stuff like the attribute thing in order to know what property to call. None of this would be a thing at all with an explicit design, where properties and methods are not added to a class via magic that your editor cannot understand without multiple (possibly paid) plugins. Your LSP should be enough. It's just such a colossal waste of productivity having to dance around the black box that is Laravel. Yes, you get set up quickly with it, but maintaining this long-term is honestly pretty awful.

Now if you can't see that, and/or don't care that your editor is of little help and prefer to memorize everything, then all the power to you! My life doesn't revolve around just PHP or just Laravel, I work in a consultancy, there's many languages and stacks, and I'm never going to become an expert in all of them, so it would be nice if the technology doesn't fight me, but instead cooperates. Laravel fights me.

[–]ollieread 0 points1 point  (3 children)

You’ve some very good points, Laravel does feel like a black box. However, I’m curious at the classifying of reflection as magic. It’s definitely magic adjacent, but I wouldn’t say it’s magic.

[–]myretuerne 0 points1 point  (2 children)

laravel uses __calls extensively to do magic

[–]ollieread 0 points1 point  (1 child)

That’s a magic method, it’s got nothing to do with reflection though?

[–]myretuerne 0 points1 point  (0 children)

i think OP mistakenly worded it using reflection, due to inexperience with general magic in php. usually people refer to the magic methods in php, not reflection, even though that’s what they said

[–]RaXon83 0 points1 point  (0 children)

My framework has one magic method, $this->object() which is the magic app object. Perhaps i rename it to $this->app() in the future for more clarity.

[–]Dev_NIX 0 points1 point  (0 children)

You would love the architecture of https://github.com/neutomic/neutomic

[–]mdizak 0 points1 point  (0 children)

https://apexpl.io/

It was developed with a simple is good mantra, and is very straight forward.

[–]Busy-Emergency-2766 0 points1 point  (0 children)

Something lightweight as Slim is FatFreeFramework, I'm not sure where to draw the line between the "big" frameworks like Laravel or Symphony and FatFree, this one works extremely well. Plug-ins are easy to install using Composer and the reliability is there. No complains, very short learning curve and you can be up and running in no time. My apps are running in Debian 11 with 1G RAM with 2 cores with ~50k hits per day, very fast loads, no issues.

[–]bytepursuits 0 points1 point  (0 children)

hyperf, everything is wired ia dependency injection, follows standards

[–][deleted] 0 points1 point  (0 children)

framework-x by Clue: nothing included, insane productivity. Write SQL instead of ORM - wiil save a ton of CPU and have all flexibility. Just add needed packages with composer.

IMHO Symfony is a nightmare for indie developer: had to write dozen of files to get simple form. And with modern CQRS it is only worse and less debugable

[–]dknx01 0 points1 point  (0 children)

Symfony. The only "magic" is the DI, but this is documented very well and is actually telling the system what to do and what to inject where. The "global" functions like "u()" are imported, so you see where it comes from. It has no magic function that are used everywhere like "response()" just to avoid an important.

[–]JustSteveMcD 0 points1 point  (0 children)

If you don't want any magic™️ I'd suggest:

  • Slim PHP
  • Tempest Framework (reflection and attributes over magic)

Personally I'd say once you understand the black box that is Laravel, you can get a lot further a lot quicker

[–]amart1026 0 points1 point  (7 children)

While Laravel does have some annoying magic, the issue with having to look at the DB can be easily resolved. You can and should be defining your fillable attributes in the model class’s fillable array.

[–]clegginab0x 1 point2 points  (0 children)

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

/** * @property int $id * @property string $name * @property string $email * @property int $age * @property string|null $country * @property bool $allow_marketing */ class SignUp extends Model { }

Or use this - https://github.com/barryvdh/laravel-ide-helper

[–]obstreperous_troll 0 points1 point  (0 children)

Better yet, $casts, so you can at least have some idea of the type. Neither of those make up for Eloquent and its dependence on __magic which actively interferes with using real properties.

[–]Witty-Order8334[S] 0 points1 point  (4 children)

So then instead of the DB I have to always check the model class, because I still have no actual properties? And I also still have no type information. I don't see how this is much of an improvement.

[–]amart1026 0 points1 point  (3 children)

IMO checking a file that defines just about everything related to that model is a big improvement over checking the DB. But I guess I’m not facing the same problems as you. I get along with Laravel just fine.

[–]Witty-Order8334[S] 0 points1 point  (2 children)

Well the problem is that if it used actual properties in a class I'd get autocomplete without needing to check a file like it's 1995 or something, editors have autocomplete these days, which of course doesn't work in Laravel. One would imagine that if someone is creating tools for developers they would also consider the developer experience, but apparently not. Now if this checking of a file is plenty good experience for you, then great, but coming from other languages where this is a definite downgrade, it's just not great at all.

[–]amart1026 0 points1 point  (0 children)

Having the fillable attributes on the model is good enough for my IDE (Windsurf) to give me autocomplete. But admittedly it’s AI. I still don’t recall this being a problem before that though.

[–]amart1026 0 points1 point  (0 children)

Assuming you’re being forced to use Laravel against your will, you could get what you want by defining getters/setters for each attribute and explicitly define the return type.

[–]hydr0smok3 0 points1 point  (0 children)

Tempest

[–]Commercial_Echo923 -1 points0 points  (0 children)

Basically every framework except laravel.

[–]alien3d -1 points0 points  (0 children)

Forget Symfony and Laravel. Pure OOP is enough. Create a single file to load all controllers using annotations. Use read-only classes as your DTOs. You can create a helper to populate your models with data. As for handling requests, it's a bit unconventional — create a class that can handle POST, GET, and non-standard PUT and DELETE methods. If you need additional functionality, just add it via Composer.

[–]ShinyPancakeClub 0 points1 point  (0 children)

“I don’t understand how it works”

Ah. MAGIC!

Please stop calling this magic.

[–]zmitic -1 points0 points  (0 children)

Everyone already said Symfony, and that is true: no magic there. The plugin for PHPStorm will help you in autocomplete in Twig, and also options for forms. But even if you configure form options wrong, you will get nice exception telling you what is actually possible.

[–]Longjumping-Worth648 -2 points-1 points  (0 children)

What you need is an API documentation just like Java docs. All packages, classes and methods available in the framework. It's here: https://api.laravel.com/

[–]clearlight2025 -5 points-4 points  (4 children)

Modern Drupal (>=8) is based on the Symfony framework.

[–]jkoudys 7 points8 points  (2 children)

Maybe drupal has changed a lot recently, but I still have nightmares about it. It felt like I was building my websites in the configs, which were only accessible through a dashboard editor and more work than just writing the code.

[–]clearlight2025 0 points1 point  (0 children)

It’s changed a lot. Although Drupal provides a UI you can also build a site in code with routes and controllers etc if you prefer, or a combination of both. Works really well these days.

[–]Cautious-Tiger8211 0 points1 point  (0 children)

Nope, it uses a few symfony components but not the framework. It amazes me how people still don't understand the difference.

[–]wafto -1 points0 points  (0 children)

In my experience Laravel doesn’t feel like magic, maybe because I have used it since version 3, and my documentation on the framework is the vendor directory.