{"id":13519256,"url":"https://github.com/nette/di","last_synced_at":"2025-05-13T17:11:39.204Z","repository":{"id":14969070,"uuid":"17693993","full_name":"nette/di","owner":"nette","description":"💎 Flexible, compiled and full-featured Dependency Injection Container with perfectly usable autowiring and support for all new PHP 8 features.","archived":false,"fork":false,"pushed_at":"2025-01-16T04:31:11.000Z","size":2451,"stargazers_count":888,"open_issues_count":28,"forks_count":70,"subscribers_count":38,"default_branch":"master","last_synced_at":"2025-05-03T02:51:54.621Z","etag":null,"topics":["dependency-injection","dependency-injection-container","di-container","factories","nette","nette-framework","php"],"latest_commit_sha":null,"homepage":"https://doc.nette.org/dependency-injection","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nette.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"dg","custom":"https://nette.org/donate"}},"created_at":"2014-03-13T03:45:21.000Z","updated_at":"2025-04-29T21:16:41.000Z","dependencies_parsed_at":"2023-12-14T13:49:14.160Z","dependency_job_id":"2af740bd-88ec-452e-91f1-6c88f899b330","html_url":"https://github.com/nette/di","commit_stats":{"total_commits":1302,"total_committers":60,"mean_commits":21.7,"dds":"0.10291858678955457","last_synced_commit":"515237532fbcf0a34f293cd2f4cdc46a6cb28837"},"previous_names":[],"tags_count":75,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fdi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fdi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fdi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fdi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nette","download_url":"https://codeload.github.com/nette/di/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253990469,"owners_count":21995774,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependency-injection","dependency-injection-container","di-container","factories","nette","nette-framework","php"],"created_at":"2024-08-01T05:01:56.437Z","updated_at":"2025-05-13T17:11:34.177Z","avatar_url":"https://github.com/nette.png","language":"PHP","readme":"[![Nette Dependency Injection](https://github.com/nette/di/assets/194960/d368a458-bac1-48b1-9b4b-7929f4bb2f98)](https://doc.nette.org/dependency-injection)\n\n[![Downloads this Month](https://img.shields.io/packagist/dm/nette/di.svg)](https://packagist.org/packages/nette/di)\n[![Tests](https://github.com/nette/di/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/di/actions)\n[![Coverage Status](https://coveralls.io/repos/github/nette/di/badge.svg?branch=master)](https://coveralls.io/github/nette/di?branch=master)\n[![Latest Stable Version](https://poser.pugx.org/nette/di/v/stable)](https://github.com/nette/di/releases)\n[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/di/blob/master/license.md)\n\n \u003c!----\u003e\n\nIntroduction\n------------\n\nPurpose of the Dependecy Injection (DI) is to free classes from the responsibility for obtaining objects that they need for its operation (these objects are called **services**). To pass them these services on their instantiation instead.\n\nNette DI is one of the most interesting part of framework. It is compiled DI container, extremely fast and easy to configure.\n\nDocumentation can be found on the [website](https://doc.nette.org/dependency-injection).\n\n \u003c!----\u003e\n\n[Support Me](https://github.com/sponsors/dg)\n--------------------------------------------\n\nDo you like Nette DI? Are you looking forward to the new features?\n\n[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)\n\nThank you!\n\n \u003c!----\u003e\n\nInstallation\n------------\n\nThe recommended way to install is via Composer:\n\n```\ncomposer require nette/di\n```\n\nIt requires PHP version 8.1 and supports PHP up to 8.4.\n\n \u003c!----\u003e\n\nUsage\n-----\n\nLet's have an application for sending newsletters. The code is maximally simplified and is available on the [GitHub](https://github.com/dg/di-example).\n\nWe have the object representing email:\n\n```php\nclass Mail\n{\n\tpublic string $subject;\n\tpublic string $message;\n}\n```\n\nAn object which can send emails:\n\n```php\ninterface Mailer\n{\n\tfunction send(Mail $mail, string $to): void;\n}\n```\n\nA support for logging:\n\n```php\ninterface Logger\n{\n\tfunction log(string $message): void;\n}\n```\n\nAnd finally, a class that provides sending newsletters:\n\n```php\nclass NewsletterManager\n{\n\tprivate Mailer $mailer;\n\tprivate Logger $logger;\n\n\tpublic function __construct(Mailer $mailer, Logger $logger)\n\t{\n\t\t$this-\u003emailer = $mailer;\n\t\t$this-\u003elogger = $logger;\n\t}\n\n\tpublic function distribute(array $recipients): void\n\t{\n\t\t$mail = new Mail;\n\t\t$mail-\u003esubject = '...';\n\t\t$mail-\u003emessage = '...';\n\n\t\tforeach ($recipients as $recipient) {\n\t\t\t$this-\u003emailer-\u003esend($mail, $recipient);\n\t\t}\n\t\t$this-\u003elogger-\u003elog('...');\n\t}\n}\n```\n\nThe code respects Dependency Injection, ie. **each object uses only variables which we had passed into it.**\n\nAlso, we have a ability to implement own `Logger` or `Mailer`, like this:\n\n```php\nclass SendMailMailer implements Mailer\n{\n\tpublic function send(Mail $mail, string $to): void\n\t{\n\t\tmail($to, $mail-\u003esubject, $mail-\u003emessage);\n\t}\n}\n\nclass FileLogger implements Logger\n{\n\tprivate string $file;\n\n\tpublic function __construct(string $file)\n\t{\n\t\t$this-\u003efile = $file;\n\t}\n\n\tpublic function log(string $message): void\n\t{\n\t\tfile_put_contents($this-\u003efile, $message . \"\\n\", FILE_APPEND);\n\t}\n}\n```\n\n**DI container is the supreme architect** which can create individual objects (in the terminology DI called services) and assemble and configure them exactly according to our needs.\n\nContainer for our application might look like this:\n\n```php\nclass Container\n{\n\tprivate ?Logger $logger;\n\tprivate ?Mailer $mailer;\n\n\tpublic function getLogger(): Logger\n\t{\n\t\tif (!isset($this-\u003elogger)) {\n\t\t\t$this-\u003elogger = new FileLogger('log.txt');\n\t\t}\n\t\treturn $this-\u003elogger;\n\t}\n\n\tpublic function getMailer(): Mailer\n\t{\n\t\tif (!isset($this-\u003emailer)) {\n\t\t\t$this-\u003emailer = new SendMailMailer;\n\t\t}\n\t\treturn $this-\u003emailer;\n\t}\n\n\tpublic function createNewsletterManager(): NewsletterManager\n\t{\n\t\treturn new NewsletterManager($this-\u003egetMailer(), $this-\u003egetLogger());\n\t}\n}\n```\n\nThe implementation looks like this because:\n- the individual services are created only on demand (lazy loading)\n- doubly called `createNewsletterManager` will use the same logger and mailer instances\n\nLet's instantiate `Container`, let it create manager and we can start spamming users with newsletters :-)\n\n```php\n$container = new Container;\n$manager = $container-\u003ecreateNewsletterManager();\n$manager-\u003edistribute(...);\n```\n\nSignificant to Dependency Injection is that no class depends on the container. Thus it can be easily replaced with another one. For example with the container generated by Nette DI.\n\n \u003c!----\u003e\n\nNette DI\n----------\n\nNette DI is the generator of containers. We instruct it (usually) with configuration files. This is configuration that leads to generate nearly the same class as the class `Container` above:\n\n```neon\nservices:\n\t- FileLogger( log.txt )\n\t- SendMailMailer\n\t- NewsletterManager\n```\n\nThe big advantage is the shortness of configuration.\n\nNette DI actually generates PHP code of container. Therefore it is extremely fast. Developer can see the code, so he knows exactly what it is doing. He can even trace it.\n\nUsage of Nette DI is very easy. Save the (above) configuration to the file `config.neon` and let's create a container:\n\n```php\n$loader = new Nette\\DI\\ContainerLoader(__DIR__ . '/temp');\n$class = $loader-\u003eload(function($compiler) {\n    $compiler-\u003eloadConfig(__DIR__ . '/config.neon');\n});\n$container = new $class;\n```\n\nand then use container to create object `NewsletterManager` and we can send e-mails:\n\n```php\n$manager = $container-\u003egetByType(NewsletterManager::class);\n$manager-\u003edistribute(['john@example.com', ...]);\n```\n\nThe container will be generated only once and the code is stored in cache (in directory `__DIR__ . '/temp'`).  Therefore the loading of configuration file is placed in the closure in `$loader-\u003eload()`, so it is called only once.\n\nDuring development it is useful to activate auto-refresh mode which automatically regenerate the container when any class or configuration file is changed. Just in the constructor `ContainerLoader` append `true` as the second argument:\n\n```php\n$loader = new Nette\\DI\\ContainerLoader(__DIR__ . '/temp', autoRebuild: true);\n```\n\n \u003c!----\u003e\n\nServices\n--------\n\nServices are registered in the DI container and their dependencies are automatically passed.\n\n```neon\nservices:\n\tmanager: NewsletterManager\n```\n\nAll dependencies declared in the constructor of this service will be automatically passed. Constructor passing is the preferred way of dependency injection for services.\n\nIf we want to pass dependencies by the setter, we can add the `setup` section to the service definition:\n\n```neon\nservices:\n\tmanager:\n\t\tfactory: NewsletterManager\n\t\tsetup:\n\t\t\t- setAnotherService\n```\n\nClass of the service:\n\n```php\nclass NewsletterManager\n{\n\tprivate AnotherService $anotherService;\n\n\tpublic function setAnotherService(AnotherService $service): void\n\t{\n\t\t$this-\u003eanotherService = $service;\n\t}\n\n...\n```\n\nWe can also add the `inject: yes` directive. This directive will enable automatic call of `inject*` methods and passing dependencies to public variables with #[Inject] attribute:\n\n```neon\nservices:\n\tfoo:\n\t\tfactory: FooClass\n\t\tinject: yes\n```\n\nDependency `Service1` will be passed by calling the `inject*` method, dependency `Service2` will be assigned to the `$service2` variable:\n\n```php\nuse Nette\\DI\\Attributes\\Inject;\n\nclass FooClass\n{\n\tprivate Service1 $service1;\n\n\t// 1) inject* method:\n\n\tpublic function injectService1(Service1 $service): void\n\t{\n\t\t$this-\u003eservice1 = $service1;\n\t}\n\n\t// 2) Assign to the variable with the #[Inject] attribute:\n\n\t#[Inject]\n\tpublic Service2 $service2;\n}\n```\n\nHowever, this method is not ideal, because the variable must be declared as public and there is no way how you can ensure that the passed object will be of the given type. We also lose the ability to handle the assigned dependency in our code and we violate the principles of encapsulation.\n\n\n \u003c!----\u003e\n\nFactories\n---------\n\nWe can use factories generated from an interface. The interface must declare the returning type of the method. Nette will generate a proper implementation of the interface.\n\nThe interface must have exactly one method named `create`. Our factory interface could be declared in the following way:\n\n```php\ninterface BarFactory\n{\n\tfunction create(): Bar;\n}\n```\n\nThe `create` method will instantiate an `Bar` with the following definition:\n\n```php\nclass Bar\n{\n\tprivate Logger $logger;\n\n\tpublic function __construct(Logger $logger)\n\t{\n\t\t$this-\u003elogger = $logger;\n\t}\n}\n```\n\nThe factory will be registered in the `config.neon` file:\n\n```neon\nservices:\n\t- BarFactory\n```\n\nNette will check if the declared service is an interface. If yes, it will also generate the corresponding implementation of the factory. The definition can be also written in a more verbose form:\n\n```neon\nservices:\n\tbarFactory:\n\t\timplement: BarFactory\n```\n\nThis full definition allows us to declare additional configuration of the object using the `arguments` and `setup` sections, similarly as for all other services.\n\nIn our code, we only have to obtain the factory instance and call the `create` method:\n\n```php\nclass Foo\n{\n\tprivate BarFactory $barFactory;\n\n\tfunction __construct(BarFactory $barFactory)\n\t{\n\t\t$this-\u003ebarFactory = $barFactory;\n\t}\n\n\tfunction bar(): void\n\t{\n\t\t$bar = $this-\u003ebarFactory-\u003ecreate();\n\t}\n}\n```\n","funding_links":["https://github.com/sponsors/dg","https://nette.org/donate"],"categories":["PHP"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnette%2Fdi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnette%2Fdi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnette%2Fdi/lists"}