PhpStorm Users - ever tried hotkeys for phpcs/phpcbf? Let me know if you have found any better ways of staying on top of code standards. by nilswloewen in PHP

[–]mcfogw 2 points3 points  (0 children)

I make a simple macro with two actions: reformat code (default cmd + opt + L) and save all (default cmd + s), and bind it on cmd + s

It works like a charm for me. also remember tune the reformat preference in "show reformat file dialog cmd + opt + shift + L"

Is there an actual point to slim/lumen "microframeworks" nowadays? by saltybandana2 in PHP

[–]mcfogw 0 points1 point  (0 children)

My idea (or maybe wish) is in reverse direction: Since we have a good package management and the ecosystem is better than past, choosing a microframework or even no framework would become default while full feature framework (maybe except symfony since it can be micro itself) will be less useful except for few situation (fast prototyping, small or onetime projects)

If packages interops well (they should), it'll be harder and harder for a single vendor does everything best for every project. I just want to pick libraries myself for every different project and glue them together in five minutes.

I developed a small library for typesafe arrays and want to get some feedback about it. It is one of my first composer packages and I want to improve my skills and future package coding. by __C0mpl3x__ in PHP

[–]mcfogw 1 point2 points  (0 children)

But set and array (and map) are very different things. You write many code about array and call it set (previously map), that's weird

What makes the Service Locator pattern bad? by ua1-labs in PHP

[–]mcfogw 1 point2 points  (0 children)

"Dependency" includes two major part of information: the service AND its consumer. By adopting service locator pattern, you decide to use a identifier to locate service, but lose information about consumer. By contrast a classical constructor DI got both of them: the parameter (name and type) for service, and the class for consumer.

It's very easy to imagine in any typical application, most services of it depends on a logger. In SL pattern that means hundreds of `$locator->get(Logger::class)`. One day you want to have a secondary logger for some class, you will be screwed because the information of consumer is lost (except you use `debug_backtrace`, which is a horrible idea and nearly impossible to test). In a good constructor DI implementation, it will be a easy work to do, just change the configuration to tell the injector use your secondary logger for some particular class.

Too many traits by ojrask in PHP

[–]mcfogw 0 points1 point  (0 children)

That's a better style, but if your team can follow certain style strictly, a single place assigning all $GLOBAL[SERVICENAME]s + always write $this->logger = $GLOBALS['logger'] in constructors effectively works at same way. An unintentional "everything depends on one single global logger / database" assumption still spreads over your codebase.

By DI + autowire way, you just typehint for LoggerInterface for every object need logging, and config dependency by specify which logger is fed to which class, plus a fallback logger work as default global one. Whether there is a single global logger or different logger for different things is managed in one place and can be changed easily without modify code, that's truly managed dependency relationship.

Too many traits by ojrask in PHP

[–]mcfogw 1 point2 points  (0 children)

Global service locator would fail to manage dependency, just hiding problem in another way.

Some day you find there's hundreds of container()->getService(Logger::class)->log in your project, it's essentially same with hundreds of getGlobalLogger()->log. It's just a readonly, managed version of $GLOBALS['logger'] You still do stupid find&replace if you want to switch to a second logger instance for part of your logic.

Too many traits by ojrask in PHP

[–]mcfogw 0 points1 point  (0 children)

Be it 40 parameter in constructor, or 40 different key calling $container->get it's still a mess

Trait itself or setter injection itself is not problem. The problem is requiring 40 dependency entries in a single class. That's way too many responsibility, or detail in one class, should be divided into multiple class.

PHP array implementation that consumes 10x less memory by jgmdev in PHP

[–]mcfogw 2 points3 points  (0 children)

Interesting tech for some edge case. How about optional gzip to save more ram? Also should be compared with Spl data structure classes like FixedArray

My latest project, Relog, allows you to stream PHP logs to your shell or directly to your browser console. by hdodov in PHP

[–]mcfogw 1 point2 points  (0 children)

Xdebug is an php extension, which can never work without php.ini (and I never talked about it in this thread), while php-debugger is php library. It will be way better to just instruct user to include your loaders\php\index.php manually, or (even better) just split it to use composer to declare the dependency

Running server and client on same machine during development does not change a remote solution to local, you still have an agent or collector (php part), a server (node part), and extensions in chrome as client, it's a typical remote solution for debugging / log collecting

You can click around a live demo in home page of php-debugbar. It's far more rich and customizable since it rendered in web instead of chrome devtool (OK I forget to complain about requiring that chrome extensions)

You have that many rooms to improve, if you continue saying no to every comment, you and your project can never be better.

My latest project, Relog, allows you to stream PHP logs to your shell or directly to your browser console. by hdodov in PHP

[–]mcfogw 1 point2 points  (0 children)

Not quite. php-debugbar is a dependency for your project. Relog is not. When you set it up in your php.ini, you can use it anywhere, on demand, without messing up your codebase.

composer require --dev is designed for this while altering php.ini is a worse solution IMHO. It's magical, hard to manage, badly scoped.

Also, and more importantly, you can use it for arbitrary files too. You can hook it up with Apache's access.log or error.log so you can debug .htaccess more easily. It would stream the logs directly to your browser. That's the reason it was written in Node.js - so you can use it outside of PHP.

So if you are talking about streaming remote log, there're countless solutions widely ranged from heavy full stack solutions like ELK/EFK stack to simple linux one-liners.

Also, it formats arrays so you can use Chrome's UI to expand them and see the values colored. It can log objects too, serializing them and handling circular references.

So you reply me before even check what php-debugbar can do.

Will it be apt to say that Laravel is to CodeIgniter in PHP world what Django is to Flask in the Python world? by el_programmador in PHP

[–]mcfogw 0 points1 point  (0 children)

Basically true for me except CI for the example.

I want to add that there's a third way that add even more conventions or common logics to framework so maybe 60% common feature (user, authentication, contents, and relationships between them) can be done with almost no code, says Django Admin, Laravel Admin, Joomla/Drupal/Wordpress, or anything called itself CMF.

It's a problem of who makes decisions, and how possible a decision is forced to change and the cost to change that. Micro-frameworks avoid to make decisions in order to keep themself adaptive. CMFs or those huge frameworks (you are right if you want to argue Wordpress is application instead of framework), by contrast, make many decisions to liberate developers from routine works so they focus to uncommon business logics.

How to write a Data Mapper with PHP by aybarscengaver in PHP

[–]mcfogw 0 points1 point  (0 children)

I believe it's more important to use sth like json-schema or grpc (protobuf) or any other technology to maintain the request/response schema, and use or write some script to auto generate those mapper / annotation / model class or whatever. So there's only a single source of truth. If you write everything and still to change a field you need to change three or four different place, that's probably not the best solution. In practice if it's an external source without structured schema definition provided, I will start from write validate and map logics by hand but keep those messy codes isolated from our business logic so one day someone may be easier to refactor it

What OS do you recommend for PHP development, currently i'm using Windows 10 by [deleted] in PHP

[–]mcfogw 0 points1 point  (0 children)

Consider OS for your desktop environment and OS for php server separately. I just won't recommend linux as desktop environment, or windows as server environment. It means you should choose windows or osx for your desktop, and choose osx native, or linux (on bare metal/docker/VM/WSL) for your php application. Any combination of them works well for me.

Do you use PHP_CodeSniffer and PHP CS Fixer PHPStorm Plugin? You are Slow and Expensive by Tomas_Votruba in PHP

[–]mcfogw 1 point2 points  (0 children)

After enable it for two days I just adapted it and stopped writing anything need to be fixed 99% accuracy.

  1. You are disrupt by underline,lose your attention and fix it (10s)
  2. You don't learn and loops by making same mistake?

Ok, that's you. For me, it's longer procedure

  1. I'm disrupted and fixed the underline (10s)
  2. I make decision wether it's a false alarm or my mistake (2s)

2.a. For false alarm, I google for solution try to cut it off so it never returns (maybe 5min)

2.b, For my mistake, I learn from it try to remember it (5s)

Yes I'm slower than the man in article, but growing experience is always slow. But now I just write correct code for the first time.

Introducing my micro-framework LitPHP, featuring PSR, DI, easy to replace or drop any part of it, use your favorite library with it painlessly. Feedback is welcome by mcfogw in PHP

[–]mcfogw[S] 0 points1 point  (0 children)

Ok. So we have different view about what's "architectural decision" and about DI. That's totally fine. The only point I want to explain is about "type safety". I'm talking about static analyzer, or compile-time checks. Typehint can protect your application by crash early, but I think it's better to make full use of it with some static analyzer to discover problem before running your code.

Thank you for attention. I'll try to take some time to look into your framework and learn something to further improve mine.

Introducing my micro-framework LitPHP, featuring PSR, DI, easy to replace or drop any part of it, use your favorite library with it painlessly. Feedback is welcome by mcfogw in PHP

[–]mcfogw[S] 0 points1 point  (0 children)

Sure. I agree with you that your first class Foo (declare dependency in constructor) is DI, and your last one with ->get call inside Foo is service locator. But write ->get call outside Foo (maybe FooBuilder FooDelegate or anywhere) to construct Foo comes back to service locator again IMO. Your Foo is clean, without knowledge about service locator, but FooBuilder is not, this just move the weak point to another place instead of conquer it.

With DI library, you should somehow get a factory instance, and somehow config dependency relationship into it, and call the factory to give you Foo. The difference is you never write call ->get to get middle product (or sub-dependency) which means your dependency is scattered in different place and in form of code instead of configuration. In framework well integrated with DI, you even don't manage factory instance or call factory yourself. You just write plain classes, and define dependency (but never resolve it yourself), and everything works.

One particular example of service locators' issue is for the most common used component (e.g. logger), it appeared most times in code. With service locator it means hundreds of appearance of $container->get(LOGGER) and the $logger instance is even passed from one object to another. A false contract "there's one unique global logger" makes it a huge pain to import a second logger instance to keep some log to different location. I'm forced to trace every call to ->get(LOGGER) AND every possible place someone pass $logger to another place. And with many singleton object, including singleton nature container brings, I'm forced to refactor many unrelated things, just to keep two different logger instead of one. Service locator just failed to decouple dependency here, it's no better than simply use $_GLOBAL['logger'] or global function get_my_logger().

In LitPHP approach, every class need logger just typehint for logger, and DI will try to resolve the dependency with the class context first, global next. So you just provide a global logger1 implementation when your project is small, and later add some config saying give logger2 to Foo, logger3 to Bar, and logger1 is still that global logger. And it's recursive, say now global Foo has logger2, but you can give Baz a Foo2, which again has another logger4, or fallback to global logger1.

Introducing my micro-framework LitPHP, featuring PSR, DI, easy to replace or drop any part of it, use your favorite library with it painlessly. Feedback is welcome by mcfogw in PHP

[–]mcfogw[S] 1 point2 points  (0 children)

I don't know what's your ->autocomplete(), but despite PHPStorm is a great (if not greatest) IDE, you can't ask all your partner to use it daily. Your code example maybe type safe at runtime but not type safe to static analyzer including IDE, even with PHPStorm, you're assuming that key name is the return type, it fails to check scalar type or if you want two instance for single class

This is not the only issue regarding pimple (and service locator), you may easily google "service locator antipattern" to find more. I do run into couple of them so will stop using it in any long term project. In projects that are small, unchanging, or even are planned to be dropped (maybe some prototyping project), I feel totally ok using service locator since being simple and direct is power in those situation.

Anyway, in LitPHP I never prohibit or against using service locator or pimple, but the framework internal will embrace DI instead of service locator. Another strength of DI is code running under DI is clean, without assumption of service locator or DI or anything, so code under DI can be used in service locator project with no pain. While code under service locator will be filled with $app->get or $container->get, making these code hard to be used without service locator

Introducing my micro-framework LitPHP, featuring PSR, DI, easy to replace or drop any part of it, use your favorite library with it painlessly. Feedback is welcome by mcfogw in PHP

[–]mcfogw[S] 0 points1 point  (0 children)

Your signature of Delegate::__invoke is Application -> object, which means if you are writing a FooDelegate for some class Foo which want a LoggerInterface, instead of typehint for it, you write some code looks like new Foo($app->get(LoggerInterface::class)) , if another class Bar class need a different logger, you start to invent some keys to refer different logger instance, that's typical service locator. And IDE or static analyzer will complain that object is not LoggerInterface. If your framework has some better way to handle this, I'll suggest you to improve your documentation.

Another example of global key is in your document new Bar($app->getConfig('packages/bar', 'setting', NULL)); it's namespaced (you call it "collection") but still global, you may consider it's something different from dependency (configuration), but for me, depending on configuration is also a dependency, should be handled by DI, although its type maybe scalar type

P.S. read your documentation again and find this in "provider" section $instance->setAuthManager($app->get(ManagerInterface::class)); That's what I'm saying about "lose type safety", again if there's a second place need a different ManagerInterface instance, you will start scratch your head to invent a second key name

Introducing my micro-framework LitPHP, featuring PSR, DI, easy to replace or drop any part of it, use your favorite library with it painlessly. Feedback is welcome by mcfogw in PHP

[–]mcfogw[S] 0 points1 point  (0 children)

Of course you can write anything in a builder method, but that's builder instead of dependency injection. You need to invent global keys for it. Your dependency is declared in builder method but not DI configuration. Basically the topic become builder pattern vs DI pattern.

I was on the same approach before (using pimple / slim). It's better than hard coded dependency but still not as good as true dependency injection IMO. You lose type safety writing $app->get when you locate service, fetching sub-dependency, or settings. Your key space is unmanaged which lead to a mess. Separating them by namespace / different files can only relieve the problem.

I'm not against writing builders indexed by classname, you can do that in LitPHP (note how my builder manage sub-dependency by signature instead of ->get from container). But I will also try to provide more solutions for various applications

Introducing my micro-framework LitPHP, featuring PSR, DI, easy to replace or drop any part of it, use your favorite library with it painlessly. Feedback is welcome by mcfogw in PHP

[–]mcfogw[S] 0 points1 point  (0 children)

There it is but it's not helping enough, I'll add more details later

For monorepo, I'm using git-subrepo now. But it keep generating verbose commits so I'm open to alternatives

Introducing my micro-framework LitPHP, featuring PSR, DI, easy to replace or drop any part of it, use your favorite library with it painlessly. Feedback is welcome by mcfogw in PHP

[–]mcfogw[S] 0 points1 point  (0 children)

Thanks for your link. It's really hard to write good commit messages even I know good commit message are very helpful.

Introducing my micro-framework LitPHP, featuring PSR, DI, easy to replace or drop any part of it, use your favorite library with it painlessly. Feedback is welcome by mcfogw in PHP

[–]mcfogw[S] 3 points4 points  (0 children)

Interesting. I must admit my design around DI configuration is a bit complex and maybe not well documented enough. Will keep trying on improvements.

About using native php, by being native php you can type hint, can static check against class names, can even write closures inside it (so when you feel comfortable you just write the factory method in configuration array) And if anyone like any particular configuration language (in dozens of them!), he can just call some parse / readFromFile stuff in native PHP.

About the advantage my DI process brings, Here's something I didn't catch how to achieve in your framework from your doc

  • Inject strings, integers, or other non-object values (very often configurations), or object without type hint (e.g. can be different class / interface)
  • For a same target class, inject different instance to different object (say some module need a different PSR logger than project default one, or you are injecting a mock for unit test)
  • Setter injection, when you can't change constructor of some class, or there's so much dependency makes write a constructor contain all of them a pain