[{"data":1,"prerenderedAt":633},["ShallowReactive",2],{"article:\u002Farticles\u002Funderstanding-service-containers-in-php":3,"article-surround:\u002Farticles\u002Funderstanding-service-containers-in-php":627},{"id":4,"title":5,"body":6,"date":615,"description":616,"draft":617,"extension":618,"meta":619,"navigation":173,"path":620,"seo":621,"stem":622,"tags":623,"__hash__":626},"articles\u002Farticles\u002Funderstanding-service-containers-in-php.md","Understanding Service Containers in PHP",{"type":7,"value":8,"toc":612},"minimark",[9,18,23,26,29,51,55,76,81,92,105,144,160,339,381,465,474,478,481,580,590,594,597,608],[10,11,12,13,17],"p",{},"One of the key concepts that we're going to discuss is the ",[14,15,16],"strong",{},"Service Container"," and how it can help manage dependencies to ensure a clean, maintainable codebase. Service containers are a core part of many PHP frameworks, such as Laravel and Symfony, but the concept itself is applicable to any PHP project.",[19,20,22],"h4",{"id":21},"what-is-a-service-container","What is a Service Container?",[10,24,25],{},"A service container, also known as a dependency injection container, is essentially a registry where you define how to create objects (services) and how they should be wired together. Instead of manually creating instances of classes and passing them around, you let the service container handle it. This approach promotes loose coupling and increases the flexibility of your application.",[10,27,28],{},"In simple terms, a service container is responsible for:",[30,31,32,39,45],"ol",{},[33,34,35,38],"li",{},[14,36,37],{},"Storing Services:"," A service can be any PHP object, typically a class instance that performs a specific task (like sending an email, handling a database connection, or logging information).",[33,40,41,44],{},[14,42,43],{},"Resolving Dependencies:"," Services often depend on other services. The service container can help automatically resolves these dependencies when a service is requested.",[33,46,47,50],{},[14,48,49],{},"Managing Lifecycle:"," Service containers can manage the lifecycle of services, deciding whether to return a new instance every time or reuse an existing one (Singleton).",[19,52,54],{"id":53},"why-use-a-service-container","Why Use a Service Container?",[56,57,58,64,70],"ul",{},[33,59,60,63],{},[14,61,62],{},"Dependency Injection:"," Instead of manually creating dependencies, the container injects them into your classes. This helps decouple your code and makes it easier to test and maintain.",[33,65,66,69],{},[14,67,68],{},"Centralised Configuration:"," All your services and their dependencies are managed in one place. This improves the structure of your code and makes it easier to update or change services.",[33,71,72,75],{},[14,73,74],{},"Flexibility and Scalability:"," As your application grows, service containers help you manage complexity by allowing you to easily swap implementations, configure services differently for different environments, or add new services without breaking existing code.",[77,78,80],"h3",{"id":79},"how-does-it-work","How Does It Work?",[10,82,83,84,91],{},"In this example, we'll break down the process into simple, digestible steps. We'll be using ",[85,86,90],"a",{"href":87,"rel":88},"https:\u002F\u002Fphp-di.org\u002F",[89],"nofollow","PHP-DI"," as the service container, but the concepts here should apply to most service containers.",[30,93,94],{},[33,95,96,99,100,104],{},[14,97,98],{},"Create the Service Container:","\nIf your framework doesn't provide a built-in service container, you'll need to create an instance of one. This is usually done early in your application's lifecycle, such as in ",[101,102,103],"code",{},"index.php"," or a dedicated bootstrap file that sets up critical services.",[106,107,112],"pre",{"className":108,"code":109,"language":110,"meta":111,"style":111},"language-php shiki shiki-themes github-dark github-light","\u002F\u002F app\u002Fbootstrap.php\n$container = new DI\\Container();\n","php","",[101,113,114,123],{"__ignoreMap":111},[115,116,119],"span",{"class":117,"line":118},"line",1,[115,120,122],{"class":121},"si27w","\u002F\u002F app\u002Fbootstrap.php\n",[115,124,126,130,134,137,141],{"class":117,"line":125},2,[115,127,129],{"class":128},"shWlK","$container ",[115,131,133],{"class":132},"spKkM","=",[115,135,136],{"class":132}," new",[115,138,140],{"class":139},"sTU5a"," DI\\Container",[115,142,143],{"class":128},"();\n",[30,145,146],{"start":125},[33,147,148,151,152,155,156,159],{},[14,149,150],{},"Register Your Definitions:","\nNext, you'll need to define the services you want to manage with the container, along with their dependencies. These definitions tell the container how to create and configure instances of your classes. For this example, we'll define a simple ",[101,153,154],{},"Router"," and ",[101,157,158],{},"RouterManager"," class. (Note: The implementation details of these classes are beyond the scope of this article and just serve as a simple example.)",[106,161,163],{"className":108,"code":162,"language":110,"meta":111,"style":111},"\u002F\u002F app\u002Fbootstrap.php\n\n\u002F**\n  * DI Container and Definitions\n  *\u002F\n$containerDefinitions = [\n    'Router' => function () {\n        return new Router();\n    },\n    'RouterManager' => function (Router $router) {\n        return new RouterManager($router);\n    },\n];\n\n$builder = new ContainerBuilder();\n$builder->addDefinitions($containerDefinitions);\n\n$container = $builder->build();\n",[101,164,165,169,175,181,187,193,204,220,233,239,257,270,275,281,286,301,317,322],{"__ignoreMap":111},[115,166,167],{"class":117,"line":118},[115,168,122],{"class":121},[115,170,171],{"class":117,"line":125},[115,172,174],{"emptyLinePlaceholder":173},true,"\n",[115,176,178],{"class":117,"line":177},3,[115,179,180],{"class":121},"\u002F**\n",[115,182,184],{"class":117,"line":183},4,[115,185,186],{"class":121},"  * DI Container and Definitions\n",[115,188,190],{"class":117,"line":189},5,[115,191,192],{"class":121},"  *\u002F\n",[115,194,196,199,201],{"class":117,"line":195},6,[115,197,198],{"class":128},"$containerDefinitions ",[115,200,133],{"class":132},[115,202,203],{"class":128}," [\n",[115,205,207,211,214,217],{"class":117,"line":206},7,[115,208,210],{"class":209},"skb7c","    'Router'",[115,212,213],{"class":132}," =>",[115,215,216],{"class":132}," function",[115,218,219],{"class":128}," () {\n",[115,221,223,226,228,231],{"class":117,"line":222},8,[115,224,225],{"class":132},"        return",[115,227,136],{"class":132},[115,229,230],{"class":139}," Router",[115,232,143],{"class":128},[115,234,236],{"class":117,"line":235},9,[115,237,238],{"class":128},"    },\n",[115,240,242,245,247,249,252,254],{"class":117,"line":241},10,[115,243,244],{"class":209},"    'RouterManager'",[115,246,213],{"class":132},[115,248,216],{"class":132},[115,250,251],{"class":128}," (",[115,253,154],{"class":139},[115,255,256],{"class":128}," $router) {\n",[115,258,260,262,264,267],{"class":117,"line":259},11,[115,261,225],{"class":132},[115,263,136],{"class":132},[115,265,266],{"class":139}," RouterManager",[115,268,269],{"class":128},"($router);\n",[115,271,273],{"class":117,"line":272},12,[115,274,238],{"class":128},[115,276,278],{"class":117,"line":277},13,[115,279,280],{"class":128},"];\n",[115,282,284],{"class":117,"line":283},14,[115,285,174],{"emptyLinePlaceholder":173},[115,287,289,292,294,296,299],{"class":117,"line":288},15,[115,290,291],{"class":128},"$builder ",[115,293,133],{"class":132},[115,295,136],{"class":132},[115,297,298],{"class":139}," ContainerBuilder",[115,300,143],{"class":128},[115,302,304,307,310,314],{"class":117,"line":303},16,[115,305,306],{"class":128},"$builder",[115,308,309],{"class":132},"->",[115,311,313],{"class":312},"sqoU-","addDefinitions",[115,315,316],{"class":128},"($containerDefinitions);\n",[115,318,320],{"class":117,"line":319},17,[115,321,174],{"emptyLinePlaceholder":173},[115,323,325,327,329,332,334,337],{"class":117,"line":324},18,[115,326,129],{"class":128},[115,328,133],{"class":132},[115,330,331],{"class":128}," $builder",[115,333,309],{"class":132},[115,335,336],{"class":312},"build",[115,338,143],{"class":128},[30,340,341],{"start":177},[33,342,343,346,347,354,355,357,358,362,363,366,367,372,373,376,377,380],{},[14,344,345],{},"Resolve Dependencies:","\nOnce your definitions are in place, you can use the service container to resolve dependencies by requesting the service you’ve defined.\n",[14,348,349,350,353],{},"How does it know what classes to inject when specified in the ",[101,351,352],{},"__constructor","?"," ",[14,356,90],{}," simplifies this with a technique called ",[359,360,361],"em",{},"autowiring",", a common feature in service containers. ",[359,364,365],{},"Autowiring"," uses ",[85,368,371],{"href":369,"rel":370},"http:\u002F\u002Fphp.net\u002Fmanual\u002Fen\u002Fbook.reflection.php",[89],"PHP's Reflection API"," to automatically determine and inject the required parameters for class constructors.\n",[14,374,375],{},"A Word on Lazy-Loading"," - You might be concerned that having large definition files could eventually slow down a sizeable PHP application. However, with lazy-loading, services are only instantiated when they are actually requested from the service container using ",[101,378,379],{},"$container->get(…)",". This means that even if you have extensive definition files, they won't negatively impact your application's performance since services are not created upfront but only when needed.",[106,382,384],{"className":108,"code":383,"language":110,"meta":111,"style":111},"\u002F**\n  * Manually Resolving Dependencies\n  *\u002F\n$router = new Router();\n$routerManager = new RouterManager($router);\n\n\u002F**\n  * Resolving Dependencies via Service Container\n  *\u002F\n$routerManager = $container->get('RouterManager');\n",[101,385,386,390,395,399,412,425,429,433,438,442],{"__ignoreMap":111},[115,387,388],{"class":117,"line":118},[115,389,180],{"class":121},[115,391,392],{"class":117,"line":125},[115,393,394],{"class":121},"  * Manually Resolving Dependencies\n",[115,396,397],{"class":117,"line":177},[115,398,192],{"class":121},[115,400,401,404,406,408,410],{"class":117,"line":183},[115,402,403],{"class":128},"$router ",[115,405,133],{"class":132},[115,407,136],{"class":132},[115,409,230],{"class":139},[115,411,143],{"class":128},[115,413,414,417,419,421,423],{"class":117,"line":189},[115,415,416],{"class":128},"$routerManager ",[115,418,133],{"class":132},[115,420,136],{"class":132},[115,422,266],{"class":139},[115,424,269],{"class":128},[115,426,427],{"class":117,"line":195},[115,428,174],{"emptyLinePlaceholder":173},[115,430,431],{"class":117,"line":206},[115,432,180],{"class":121},[115,434,435],{"class":117,"line":222},[115,436,437],{"class":121},"  * Resolving Dependencies via Service Container\n",[115,439,440],{"class":117,"line":235},[115,441,192],{"class":121},[115,443,444,446,448,451,453,456,459,462],{"class":117,"line":241},[115,445,416],{"class":128},[115,447,133],{"class":132},[115,449,450],{"class":128}," $container",[115,452,309],{"class":132},[115,454,455],{"class":312},"get",[115,457,458],{"class":128},"(",[115,460,461],{"class":209},"'RouterManager'",[115,463,464],{"class":128},");\n",[10,466,467,468,473],{},"For more details on PHP-DI and general service container concepts, check out the official ",[85,469,472],{"href":470,"rel":471},"https:\u002F\u002Fphp-di.org\u002Fdoc\u002Fgetting-started.html",[89],"documentation",".",[19,475,477],{"id":476},"example-in-laravel","Example in Laravel",[10,479,480],{},"Laravel’s service container is powerful and easy to use. Here's an example of registering and resolving a service:",[106,482,484],{"className":108,"code":483,"language":110,"meta":111,"style":111},"\u002F\u002F Binding a service\napp()->bind('App\\Services\\PaymentGateway', function($app) {\n    return new PaymentGateway($app->make('App\\Services\\Logger'));\n});\n\n\u002F\u002F Resolving a service\n$paymentGateway = app()->make('App\\Services\\PaymentGateway');\n",[101,485,486,491,518,544,549,553,558],{"__ignoreMap":111},[115,487,488],{"class":117,"line":118},[115,489,490],{"class":121},"\u002F\u002F Binding a service\n",[115,492,493,496,499,501,504,506,509,512,515],{"class":117,"line":125},[115,494,495],{"class":312},"app",[115,497,498],{"class":128},"()",[115,500,309],{"class":132},[115,502,503],{"class":312},"bind",[115,505,458],{"class":128},[115,507,508],{"class":209},"'App\\Services\\PaymentGateway'",[115,510,511],{"class":128},", ",[115,513,514],{"class":132},"function",[115,516,517],{"class":128},"($app) {\n",[115,519,520,523,525,528,531,533,536,538,541],{"class":117,"line":177},[115,521,522],{"class":132},"    return",[115,524,136],{"class":132},[115,526,527],{"class":139}," PaymentGateway",[115,529,530],{"class":128},"($app",[115,532,309],{"class":132},[115,534,535],{"class":312},"make",[115,537,458],{"class":128},[115,539,540],{"class":209},"'App\\Services\\Logger'",[115,542,543],{"class":128},"));\n",[115,545,546],{"class":117,"line":183},[115,547,548],{"class":128},"});\n",[115,550,551],{"class":117,"line":189},[115,552,174],{"emptyLinePlaceholder":173},[115,554,555],{"class":117,"line":195},[115,556,557],{"class":121},"\u002F\u002F Resolving a service\n",[115,559,560,563,565,568,570,572,574,576,578],{"class":117,"line":206},[115,561,562],{"class":128},"$paymentGateway ",[115,564,133],{"class":132},[115,566,567],{"class":312}," app",[115,569,498],{"class":128},[115,571,309],{"class":132},[115,573,535],{"class":312},[115,575,458],{"class":128},[115,577,508],{"class":209},[115,579,464],{"class":128},[10,581,582,583,585,586,589],{},"Much like ",[14,584,90],{}," Laravel's service container also supports ",[359,587,588],{},"auto-wiring",", meaning you often don’t need to manually bind or resolve services.",[19,591,593],{"id":592},"conclusion","Conclusion",[10,595,596],{},"Service containers are a fundamental part of building modern, scalable, and maintainable PHP applications. By managing your services and their dependencies in a centralised and organised manner, you can significantly improve your code’s flexibility and testability.",[10,598,599,600,603,604,607],{},"Whether you’re using a framework like ",[14,601,602],{},"Laravel"," or ",[14,605,606],{},"Symfony",", or building your own custom solution, understanding and leveraging service containers will help you write cleaner, more efficient PHP code.",[609,610,611],"style",{},"html pre.shiki code .si27w, html code.shiki .si27w{--shiki-default:#6A737D;--shiki-light:#6A737D}html pre.shiki code .shWlK, html code.shiki .shWlK{--shiki-default:#E1E4E8;--shiki-light:#24292E}html pre.shiki code .spKkM, html code.shiki .spKkM{--shiki-default:#F97583;--shiki-light:#D73A49}html pre.shiki code .sTU5a, html code.shiki .sTU5a{--shiki-default:#79B8FF;--shiki-light:#005CC5}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .skb7c, html code.shiki .skb7c{--shiki-default:#9ECBFF;--shiki-light:#032F62}html pre.shiki code .sqoU-, html code.shiki .sqoU-{--shiki-default:#B392F0;--shiki-light:#6F42C1}",{"title":111,"searchDepth":125,"depth":125,"links":613},[614],{"id":79,"depth":177,"text":80},"2024-08-20","How dependency injection containers store services, resolve their dependencies, and manage lifecycles - built up from scratch with a worked PHP-DI example.",false,"md",{},"\u002Farticles\u002Funderstanding-service-containers-in-php",{"title":5,"description":616},"articles\u002Funderstanding-service-containers-in-php",[110,624,625],"architecture","dependency-injection","X8wcBgoNXhFS7N28Q5x2PdtOeS_0LiwKAoZp_uXDEfo",[628,632],{"title":629,"path":630,"stem":631,"children":-1},"Skinny Controllers, Fat Models","\u002Farticles\u002Fskinny-controllers-fat-models","articles\u002Fskinny-controllers-fat-models",null,1782332463146]