In the previous post, we learned that Reflection allows PHP to inspect classes at runtime. But Reflection only tells us what a class needs. It doesn't create those dependencies. That's the job of Dependency Injection (DI). Let's start with an example. class UserController { private UserService $service; public function __construct() { $this->service = new UserService(); } } At first glance, this looks fine. But imagine UserService changes. Today it has no constructor. Tomorrow it requires a repository. class UserService { public function __construct( private UserRepository $repository ) {} } Now your controller breaks. You must go back and edit it. class UserController { public function __construct() { $this->service = new UserService( new UserRepository() ); } } A month later... UserRepository now needs a database connection. new UserService( new UserRepository( new DatabaseConnection(...) ) ); Every change in the dependency chain forces you to revisit code that shouldn't even care how those objects are created. This is called tight coupling. Instead, let the class declare what it needs. class UserController { public function __construct( private UserService $service ) {} } Now the controller doesn't know—or care—how UserService is created. It simply receives one that's ready to use. That's Dependency Injection. The responsibility of creating objects is moved outside the class. In the next post, we'll answer the obvious question: If the controller no longer creates UserService... who does? #PHP #Laravel #DependencyInjection #SOLID #BackendDevelopment
Dependency Injection in PHP: Decoupling Classes
More Relevant Posts
-
PHP 8.5 made closures inside attributes legal. The interesting question was what closures in attributes are actually for. Every declarative framework has the same weak spot: the first value that has to be computed. A message delay that depends on the command. A deduplication key derived from the payload. Until now you had two options, and both were taxes. Option one: expression language strings like 'payload.delayInMilliseconds'. Rename the property and it breaks at runtime. PHPStan sees a string. Your IDE sees a string. So there is no native support for veryfing correctness of those. Option two: leave the declarative model and write a middleware class for one line of logic. Meaning extra classes, configuration and wiring, even for simple things like delaying the execution. Ecotone supports both, but thanks to closures in attributes provides now a third path. Every "expression" property now accepts a real Closure, and the closure executes like a message handler: parameters resolve via #[Payload] with conversion, #[Header] by name, #[Reference] for services. The framework does the plumbing, so the closure body stays one line. Under the hood, the container stores a reference to the declaring class or method and re-reads the attribute via reflection at runtime, since PHP still cannot serialize closures. As a result we get: → Typed, refactorable, IDE-completable inline expressions → Logic lives together, so it's easy to follow what to expect from code → Ability to access different context, like payload, headers, services without rolling separate middlewares #PHP #Ecotone #SoftwareArchitecture
To view or add a comment, sign in
-
-
PHP rejected generics last week. The internet said “dead” again. The real story is way more interesting. The facts: the “Bound-Erased Generic Types” RFC went to a vote from June 14 to 28. It lost, roughly 4 yes to 12 no. Cue every “PHP is behind” account taking a victory lap. Here’s the plot twist: you’ve been using generics in PHP for about a decade. PHPDoc with @template, checked by PHPStan or Psalm, is erased generics. Your static analyzer enforces them today. And the language everyone compares PHP to? TypeScript erases generics too. They vanish at runtime. The exact thing PHP gets mocked for is how the trendy option already works. Funny how that part never trends. So why the “no”? It wasn’t backwardness. It was a stance. The core argument (credit to Rowan Tommins and others): if something looks like a native type, the engine should actually enforce it. They didn’t want type annotations you can’t trust. Doing reified generics properly is a real engineering bill, not a refusal. A 30-year-old language that won’t ship a half-baked version of a feature is a language I trust in production. Was it the right call, or is PHP being too conservative? Tell me below.
To view or add a comment, sign in
-
A real bug PHP 8.5 #[\NoDiscard] can help catch: Bulk imports. Imagine a CSV user import. The import method creates valid users, skips invalid rows, and returns an ImportReport containing failed rows. But someone writes: $importer->import($csvRows); The code runs. No exception. Most users are created. The dashboard says “import completed.” But 37 rows failed silently because nobody checked the returned report. With PHP 8.5, we can mark that method: #[\NoDiscard('Import can partially fail. Check the returned report.')] Now PHP warns if the caller ignores the result. That’s the real value of #[\NoDiscard]: not fancy syntax, but catching “everything ran, but we ignored the important result” bugs. Useful for: - bulk imports - payment results - validation results - immutable object updates - API calls with partial failures Small feature. Very practical. Would you use #[\NoDiscard] in your own libraries or application code? #PHP #PHP85 #BackendDevelopment #SoftwareEngineering #CleanCode
To view or add a comment, sign in
-
I noticed that the php-shared host version did not have functions to edit entities before approval. This has now been fixed. The PHP edition now has full entity editing: Changes committed: • php/src/Router.php - Added entityEdit() and entityUpdate() handlers with routes • php/templates/entity_edit.php (new) - Full edit form with Save/Save & approve/Save & reject • php/templates/entities.php - Added Edit link column • installers/php-host/bkbs-php-edition.zip - Rebuilt with changes Features added: • Click "Edit" on any entity row → opens edit form • Edit all fields: name, type, description, status, trust level, notes, JSON fields • Three save buttons: "Save changes", "Save & approve", "Save & reject" • Bulk approve/reject still works as before Github Repository: https://lnkd.in/dXuw_Uzx
To view or add a comment, sign in
-
-
Your $appends attribute just fired 500 COUNT queries, and eager loading can't save you. $appends runs PHP once per model. Serialize a collection of 500 users and that unread_count getter runs 500 times, one query each. And you can't eager load it, the attribute is computed after the models are already hydrated. Push the computation into SQL instead. A correlated subquery becomes a real column, calculated per row inside the one query that loads your users: $users = User::query() ->addSelect(['unread_count' => Message::selectRaw('count(*)') ->whereColumn('user_id', 'users.id') ->where('read', false), ]) ->get(); Now the part people miss. It's a real column now, so you can orderBy it and paginate by it. An appended attribute can't do either, it's computed in PHP after the page is already sliced. One trap to know. If you build the subquery with the query builder like above, users.* stays. But wrap it in DB::raw, or call select() to pick specific columns somewhere on that query, and the base columns drop. Your models come back holding only the computed field. When in doubt, select the base columns explicitly. Limit: the subquery has to return one row, one column. Counts, sums, latest timestamp, exists checks all fit. For actual collections you still eager load. Where are you still paying for $appends that could be a column? #Laravel #PHP #Eloquent #Database #BackendDevelopment
To view or add a comment, sign in
-
-
𝗪𝗵𝘆 𝗘𝗻𝘃𝗶𝗿𝗼𝗻𝗺𝗲𝗻𝘁 𝗩𝗮𝗿𝗶𝗮𝗯𝗹𝗲𝘀 𝗙𝗮𝗶𝗹 𝘁𝗼 𝗦𝘂𝗽𝗽𝗿𝗲𝘀𝘀 𝗪𝗣-𝗖𝗟𝗜 𝗪𝗮𝗿𝗻𝗶𝗻𝗴𝘀 Environment variables often fail to stop PHP Deprecated warnings in WP-CLI. I found this issue on Xserver. An agency reported that plugin lists were failing due to massive amounts of Deprecated messages. The problem is the execution path. On Xserver, the command /usr/bin/wp is a phar binary. It uses a shebang line: #!/usr/bin/env php. This creates a specific startup sequence: - The shell runs /usr/bin/wp. - The env command finds PHP and starts it. - PHP loads the phar and runs WP-CLI. Because the system starts PHP through a shebang, WP-CLI never reads the WP_CLI_PHP_ARGS variable. The variable never reaches the PHP startup process. I tested two methods: 1. Using the variable: 407 Deprecated lines remained. 2. Using the -d flag directly with the PHP binary: 0 lines remained. To fix this, I implemented a three-part structural solution in v1.6.8. Pillar 1: Direct Flag Injection The code now inspects the wp_cli_path. If the path starts with php, php8.2, or any php variant, it injects the -d error_reporting flag immediately after the binary. If it is a bare wp or phar command, it leaves it alone. Pillar 2: JSON Extraction Even with suppressed warnings, other noise can appear in stdout. Instead of parsing the entire string, the code now locates the first [ or { and the last ] or }. It only sends that specific range to the JSON parser. Pillar 3: Unified Error Handling I updated all code to return a tuple containing both the parsed data and the raw stdout. This ensures that if a parse fails, the original output remains available for logs and debugging. I added 51 new tests to cover these changes. These tests check PHP detection, flag positioning, and various JSON noise scenarios. When an environment variable fails, do not just try new configurations. Ask if the variable ever reaches its destination. Source: https://lnkd.in/gKtUxFeg
To view or add a comment, sign in
-
I've learned a valuable lesson from optimizing database queries in my Laravel projects - sometimes, the simplest approach can have a significant impact on performance. By using eager loading to reduce the number of queries, I've seen noticeable improvements in page load times. However, it's essential to balance this with the potential increase in memory usage. What's one optimization technique that's made a significant difference in your project's performance? #Laravel #PHP #SoftwareEngineering #BackendDevelopment #WebDevelopment #DatabaseOptimization #PerformanceMatters
To view or add a comment, sign in
-
-
Is modern PHP quietly turning into one of the cleanest backend languages out there? For years, writing clean domain entities or Data Transfer Objects (DTOs) in PHP meant writing the same repetitive ritual: * Declare a private or protected property. * Write a public getter method just to read it. * Write a public setter method with validation logic just to update it. You’d end up with a 100-line class where 80 lines were just accessors and mutators. Enter Property Hooks and Asymmetric Visibility in PHP 8.4+. Now, instead of bloated getter/setter patterns, we can do this directly on the property declaration: class UserDTO { // Publicly readable, but can only be modified internally! public private(set) string $email; // Direct getter hook with formatting logic public string $name { get => ucfirst($this->name); set => trim($value); } } No extra methods. No noise. Just clear, self-documenting intent. Pair this with Laravel's modern architecture, and building robust, strongly typed backend systems feels completely refreshed. It almost makes you look back at PHP 5/7 code like a distant, chaotic memory. Question for my network: Have you started refactoring your DTOs or domain models to use property hooks and asymmetric visibility, or are you still keeping traditional methods in your codebases? #PHP #Laravel #BackendDevelopment #CleanCode #SoftwareEngineering #WebDev
To view or add a comment, sign in
-
This is a truly amazing article on PHP attributes. It goes over ways to simplify the codebase and, equally important, when not to use them and which pitfalls to avoid.
To view or add a comment, sign in
-
𝐏𝐇𝐏 ... 𝐨𝐩𝐞𝐫𝐚𝐭𝐨𝐫: 𝐬𝐦𝐚𝐥𝐥 𝐬𝐲𝐧𝐭𝐚𝐱, 𝐛𝐢𝐠 𝐟𝐥𝐞𝐱𝐢𝐛𝐢𝐥𝐢𝐭𝐲 The ... operator in PHP is more than just unpacking. It helps write cleaner and more flexible code in multiple ways. You can use it for: 𝐀𝐫𝐠𝐮𝐦𝐞𝐧𝐭 𝐮𝐧𝐩𝐚𝐜𝐤𝐢𝐧𝐠: pass array values directly into a function. function sum($a, $b, $c) { return $a + $b + $c; } $values = [10, 20, 30]; echo sum(...$values); // 60 𝐕𝐚𝐫𝐢𝐚𝐝𝐢𝐜 𝐩𝐚𝐫𝐚𝐦𝐞𝐭𝐞𝐫𝐬: accept any number of arguments in a function. function sum(...$numbers) { return array_sum($numbers); } echo sum(10, 20, 30, 40); // 100 𝐀𝐫𝐫𝐚𝐲 𝐮𝐧𝐩𝐚𝐜𝐤𝐢𝐧𝐠: merge arrays in a readable way. $frontend = ['HTML', 'CSS']; $backend = ['PHP', 'Laravel']; $skills = [...$frontend, ...$backend]; Cleaner than calling array_merge(). A small operator, but a very useful one in real-world PHP development. #PHP #Laravel #Backend #WebDevelopment #Unpacking #Programming #PHP8 #CodingTips #SoftwareEngineering #Array #SpreadOperator #UnpackingOperator
To view or add a comment, sign in
-
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development
Impressive ❤️❤️