{"id":18864464,"url":"https://github.com/marcosh/fundic","last_synced_at":"2026-02-11T09:30:15.373Z","repository":{"id":62523852,"uuid":"94773849","full_name":"marcosh/fundic","owner":"marcosh","description":"PHP purely functional dependency injection container","archived":false,"fork":false,"pushed_at":"2017-08-30T20:34:27.000Z","size":32,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-12-30T21:30:15.421Z","etag":null,"topics":["container-interop","dependency-injection","functional","functional-programming","php","php-library"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marcosh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-19T12:22:38.000Z","updated_at":"2021-10-15T15:27:57.000Z","dependencies_parsed_at":"2022-11-02T10:31:28.140Z","dependency_job_id":null,"html_url":"https://github.com/marcosh/fundic","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosh%2Ffundic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosh%2Ffundic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosh%2Ffundic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marcosh%2Ffundic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marcosh","download_url":"https://codeload.github.com/marcosh/fundic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239808525,"owners_count":19700451,"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":["container-interop","dependency-injection","functional","functional-programming","php","php-library"],"created_at":"2024-11-08T04:41:47.130Z","updated_at":"2026-02-11T09:30:15.342Z","avatar_url":"https://github.com/marcosh.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fundic\n\n[![Latest Stable Version](https://poser.pugx.org/marcosh/fundic/version)](https://packagist.org/packages/marcosh/fundic)\n[![Build Status](https://travis-ci.org/marcosh/fundic.svg?branch=master)](https://travis-ci.org/marcosh/fundic)\n[![Code Climate](https://codeclimate.com/github/marcosh/fundic/badges/gpa.svg)](https://codeclimate.com/github/marcosh/fundic)\n[![Coverage Status](https://coveralls.io/repos/github/marcosh/fundic/badge.svg?branch=master)](https://coveralls.io/github/marcosh/fundic?branch=master)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/80cfd863dbd744e5af524c93f47967a4)](https://www.codacy.com/app/marcosh/fundic)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/marcosh/fundic/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/marcosh/fundic/?branch=master)\n\nA purely functional Dependency Injection Container for PHP\n\n## Install\n\nAdd `fundic` as a dependency to your project using [Composer](https://getcomposer.org) running\n\n```bash\ncomposer require marcosh/fundic\n```\n\n## Tests\n\nRun the tests using\n\n```bash\nphp vendor\\bin\\phpunit\n```\n\n## Theory\n\nIn its essence a dependency injection container is just a component which is able, from a key, to\nretrieve a corresponding working object.\n\nA common approach to do this is to configure how the corresponding object should be contructed or even\nrelay on autowiring based on class naming.\n\nAnother approach si to see a dependency injection container as a map that associates to a key a factory\nwhich builds the object identified by the key, possibly using recursively the container itself.\n\n`fundic` takes this idea to its core and, in fact, if you look at the essence, it is just a map\nthat associates keys to factories of the form\n\n```php\ninterface ValueFactory\n{\n    /**\n     * @return mixed\n     */\n    public function __invoke(ContainerInterface $container, string $name);\n}\n```\n\n## Basic usage\n\n### Instantiate\n\nActually `fundic` gives you two containers:\n\n- `Psr11Container` which implements the specifications of [PSR-11](https://github.com/container-interop/fig-standards/blob/master/proposed/container.md);\n- `TypedContainer`, a more type safe version\n\nYou can create a new instance of them just by calling their static method `create`:\n\n```php\n$container = TypedContainer::create();\n```\n\nThis will create an empty instance of the container that you can fill as you like.\n\n### Configure\n\nAn empty container is not really useful. You could add new entries to the container using\n\n```php\n$container = $container-\u003eadd($key, $factory);\n```\n\nwhere `$key` is a string and `$factory` is an instance of `ValueFactory`.\n\nBe aware that `$container` is immutable and that `add` returns a new instance. Therefore it is\nreally important that you remember to assign its result to a variable.\n\n### Retrieve\n\nBoth `Psr11Container` and `TypedContainer` implement\n[`Psr\\Container\\ContainerInterface`](https://github.com/php-fig/container/blob/master/src/ContainerInterface.php)\n(even if `TypedContainer` is just respecting the signature of the methods and not conforming to the annotations),\ntherefore you can query them using the `set` and `has` methods as follows\n\n```php\n// create a new empty container\n$container = Psr11Container::create();\n\n// instructs the container on how to build the object\n// associated with the provided key\n$container = $container-\u003eadd('foo', $factory);\n\n$container-\u003ehas('foo'); // returns true\n\n$object = $container-\u003eget('foo'); // retrieves the object associated to the key\n```\n\n## Container return values and exceptions\n\n`Psr11Container` works as a standard container and conforms completely to the specifications of\n[PSR-11](https://github.com/container-interop/fig-standards/blob/master/proposed/container.md).\nHence, the result of any call to the `get` method is the expected object.\n\n`Psr11Container::get` also throws exceptions if a key is not found or if there is an error while\nbuilding the return value.\n\nOn the other hand, `TypedContainer` alone does not totally conform to the specifications of\n[PSR-11](https://github.com/container-interop/fig-standards/blob/master/proposed/container.md),\nspecifically in the return values of `get` and the handling of the exceptions.\n\nIn order to make the code purely functional and to avoid unwanted side effects, the result\nof `get` is not directly the desired object, but a `Result` data structure which could\nhave the following values:\n\n- `Just`, which is a wrapper around the desired value that can be retrieved using `Just::get`;\n- `NotFound`, which represents the fact that such an entry is not present in the container;\n- `Exception`, which represents the fact that something wrong happened while invoking the factory;\n\nThese above are just values and you could do whatever you want with them (immediately react to them,\npass them around, etc ...)\n\n## Factories\n\nSome factories are provided to ease the creation of `Fundic\\Factory\\ValueFactory` instances.\n\nIt goes without saying that you could provide your own ad-hoc implementations of `Fundic\\Factory\\ValueFactory`.\n\n### ConstantFactory\n\nIf you need to store in the container a constant value, may it be a native data type, an array\nor an object, you could use the `Fundic\\Factory\\ConstantFactory` as follows:\n\n```php\n$value = // your constant that needs to be stored in the container\n\n$container-\u003eadd('foo', new ConstantFactory($value));\n\n$container-\u003eget('foo');\n```\n\nThe `ConstanctFactory` class wraps the value in a `Fundic\\Factory\\ValueFactory` which always returns\nthe provided value.\n\n### ClassNameFactory\n\nIf you need to retrieve from the container an object with no (or only optional) dependencies, you could\nuse a `Fundic\\Factory\\ClassNameFactory`, passing to it just the class name, as follows:\n\n```php\nclass Foo { ... } // no non optional dependencies in the constructor\n\n$container-\u003eadd(Foo::class, new ClassNameFactory(Foo::class));\n\n$container-\u003eget(Foo::class);\n```\n\nThe `ClassNameFactory` just calls `new` on the provided class name and returns a new instance of the class.\n\n### Callable factory\n\nThe most generic `Fundic\\Factory\\ValueFactory` implementation that we provide is `Fundic\\Factory\\CallableFactory`,\nwhich just wraps any callable with the same signature of `ValueFactory` (i.e. it needs to have as input\nparameters a `Psr\\Container\\ContainerInterface` and a `string` which is the class name). For example:\n\n```php\n$callable = function (ContainerInterface $container, string $name) { ... };\n\n$container-\u003eadd(Foo::class, new CallableFactory($callable));\n\n$container-\u003eget(Foo::class);\n```\n\n## Factory decorators\n\nSometimes you want to modify how a specific key is built and retrieved from the container without touching\nthe provided factory.\n\nAn easy mechanism to allow this possibility is to use the decorator pattern. This means that we wrap\nour factory with another factory which receives the first factory as a constructor argument.\nIn functional terms, suppose we have a factory `f` for a specific `foo` key\n(i.e. `f : (ContainerInterface, string) -\u003e foo`); what we do is passing the whole `f` to `g` where\n`g(f) : (ContainerInterface, string) -\u003e foo`.\n\nThis allows us to modify the result of the inner factory before returning it, or even avoiding to call\nthe inner factory and return a newly built value.\n\nYou could provide your own factory decorators to create complex workflows for object creations. Decorators\nare highly composable, so you could use several of them to build a single object.\n\nSome decorators of common use are provided by the library.\n\n### Memoize\n\nIf you want to retrieve the same instance of an object every time you ask a particular key to the container,\nyou need to store the result obtained the first time somewhere and the return that instead of creating\na new instance every time.\n\nThis is exactly what the `Memoize` decorator does. The first time it calls the inner factory to build the object,\nand then always returns that particular instance.\n\n```php\nclass Foo { ... }\n\n$container-\u003eadd(Foo::class, new Memoize(new ClassNameFactory(Foo::class)));\n\n$container-\u003eget(Foo::class); // a new instance of Foo is built and returned\n$container-\u003eget(Foo::class); // the same instance of Foo is returned\n```\n\n### Proxy\n\nIf the building process of a object is particularly heavy, you could desire to postpone it until the very last\nmoment when you are sure you need an instance of that particular object.\n\nTo do this you could proxy your object and initially return a wrapper that will build the actual object only\nonce a method is called on it.\n\nYou could do this using the `Proxy` decorator, as follows:\n\n```php\nclass Foo { ... } // class which is heavy to build\n\n$container-\u003eadd(Foo::class, new Proxy(new ClassNameFactory(Foo::class)));\n\n$foo = $container-\u003eget(Foo::class); // returns a proxy\n\n$foo-\u003ebar(); // here we really instantiates Foo and call the bar method on it\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcosh%2Ffundic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarcosh%2Ffundic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarcosh%2Ffundic/lists"}