{"tag":"dependencies","articles":{"projects\/avris-container":{"key":"projects\/avris-container","type":"article","published":true,"meta":{"createdAt":"2018-01-09T20:22:03+01:00","publishedAt":"2018-01-09T20:21:00+01:00","group":null,"links":[{"icon":"brands gitlab","colour":"primary","url":"https:\/\/gitlab.com\/Avris\/Container","displayUrl":null}],"category":"projects","subcategory":null,"slug":"avris-container"},"content":{"en":{"slug":"avris-container","title":"Avris Container","intro":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-container_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHlklEQVRIiX2XyY8kRxXGf2+JyKyqruplZnq8zoA3MAYsNmFkIYwlLwgBAsRikBAc4ADiwJ\/AnRsHBOIMJ8TFgAQCgS3ZEptYjbEweLwNlsczvVR3V1dmxOOQNW0EiFBGZkoZyxffFy\/el3LuNXdElIoQRK0QFXOnlkIQqAiuhqmS3Fkuj6m1QgREIICIIAxFRBARILhaImJV68mTqIiAimDumAhNM8IjhIig1IIECFBKQRgGVtUBqCjUSlKlX02AyKodJ+1FAARVeXVyufouRC2IGhGv9jOEpIbWgl\/tIChBJQI0BNFhMkJQdUDoS8UQFCFEMdUVG8NCkOHb6lrdDHdjuewQgYhhgSKKrvqaKm5GUsVDFGpZETwwQgQSgqrhppgIJoqbIlGptVJrGQZwH1ZfK6p2IpWKELUSBOsbG+xcvgJUCEEcohZUBQLMlGRG8quABFCBumJLQERXMhiKYmZkS4ybBqLn8OiIxp0mOdkTtVZK6elLAWHYL7UCcO3ZbY7350AdSItANa9AKaaDxNkUF01EdEgYSEVPNqmgZgO1llBRVAwVZ9JM2Bytc2W+i4YSJWg8oZ4hCiFC33cDQwLnz53jn888i0ggAaaCEEBCJFaSKckU15Tpg1XE2NVYAdWBHTVMjexOtoRiiCSanHjtmTUODuccdx1nr9lmeXTIfG8fEyG7UqNy9\/3v4eknnmSWG4IYIgtQHURRBRFIpmQ3PDQhaSUXQg0wUVQNFcXNcTWyZ1yEZE6SRNKGra11PvLZj7G1ucHPv\/cjnrvwHNaskXyIpun6Gnff+x7+\/IvH2GhHQCEiBjAqqICZYDqw5i44uUF6p9ZY6QugiBpqjojh5qgm3GxVE\/e879089KVP8NSv\/8LDX\/8uicJt115H1Mr+wRzPxqe\/+hV+\/f0fcsNsxrJ01OiJKIN0uoquNOyhnBRTcGkn1K4gtQ7nUABiiDhqiWSOqpHMaVNm7M7nvvhRHvjwPcyv7PPDbz5M1hGb45abb7mOg91L7B4uuPfLnyKpUC88z+uv3WZ+dMiiX1JqT6kdaCW5YSa4K8mFlAyX8QxZ9lAqAcMeQRFJqBjiiaxOmxLjlHjoM\/fxwIfvAeAPj\/6JRMN0bcrauGH\/8hHn3\/5m7v\/A3Xjb8PjXvs326XU0Onb3gr5PlBgAhVRUg5QddyElxbPgMppC7qGAhEIogoI4aMLUSebklLjzztfywY+\/9yQl7L0059TZM1x\/fpvzd9zIjW+9icnpGRHBcz9+hMkoU+oabdOTmwpSqdHR90uidqiBamBu5MbxJDjTdegLETKAiSG6DMc1oTiyOgA\/84X3nZzMAA9+\/j7+s0QELzzyG5YvX+LMa05xvJvpDnaYaYdYRSyotaP2xwg9aoK5knLGmwbX6ZRUGPIMioeSMLI4OYysRkZ5653nuP76rf8C8O+llsLTP\/kV+089TTtR2vUxZ26\/gX53wt5FQWWJ0IFkoiRE6hBhybGcsWaETzemlAKsGDIED6cVo0VpMZoq3PXOW\/4vmPnLuzzxg8dYvvIyowZQ6I4OOXylw2XJeL2hdmU4ewxUErKSS92x3KLNCL9ma0TfB7VADUVDUYwUQsJoQ2mKcNtNp\/8nkKO9Q\/766J944bdPkqVj1NYhdVSIDuqxQaPkkRJJMYmVTAk1xVJGc4OkBvIIf+N2w+GiY3lcWPaVUiqlViQEiYoVwUQ4vTk+AXEwP+LCUy\/wzO\/\/zgt\/\/gdNdIy9EKngVLJWQgMsYDnkSklB8sBNMBM0JSS3kAxyhtyAt\/gHNl\/kYFGZzzv2DirzPtg\/hsMlLDpY9kLp4Vvf+A5HB0fsXNrj4PIeuRQShUSl1crIeiYpmLWV5bjCNEghtDbYDCkd6oFlw2rQdYYxpTs2tE3sXhnT0SL33HE6Zm1isRisklsmxKk4IYmCUzXTVwhR1BObm6fY29nFzWhSovGES2VrfQLHB0wznJkE124Wtk8bk4nw7MUd5kdHlNyxcd31\/OKnv+SZi8fM2sr29pTjLnj8iQNkbWMrNGVEDUsJb1pEDc8NnjKWGlSN3LSYJ971trdw8dIut95wltJVmmZE45mttTGH+wdMsjNrE9Ns7D1\/gTVZsDmBpD3JejYmPbfdOWbn4pyXL+4xHYFLz5m77uPwjz\/Db\/\/QJ2nWZvQV2skUTw2qjpiTPCFiCEPekRB8NuGmc7A1m7C7e0DfdUzHI3p3sAn7xx21KseLYFG3kFbJyWhTpVpl0VQ622DrdbAz\/ztpJDTe0185ZO0ND+AFY354BJZY7u8jcgDo4IViMOCDFwIplUsvVqRW6mIBtZDNkBJIBFYLicEbj1NmmpypO+tNYpwE18I4w3zR8Y43zXj+ilIv98xGMN15kVsffAt+5cLfWHYd6plaKt6M4NV\/CATwlFBVJIKogcYAQGtF+v7E4NfuGBdj56VnaXOLi7C+NuPUbAOPyuHhHpuzKb970vnnhREv7S545pUFoxw0uuT9\/fPI6Ztvj1oK\/XJJ7Y5JkykSQlku0NQM6aD2eG4BBs8NaA0UQeKqhx68uEYgVEwEV8EFlEo2QzXo+w6hsD111lvj8tFgcxuHu87DvwCrEznQnIJIIAAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-container_small.png\u0022 alt=\u0022\u0022 class=\u0022border-bottom\u0022 width=\u0022480\u0022 height=\u0022320\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA dependency injection container with autowiring\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","content":"\u003Cfigure\u003E\n                \u003Cnoscript\u003E\n                    \u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-container_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E                \n                \u003C\/noscript\u003E\n                \u003Cspan class=\u0022hide-noscript\u0022\u003E\u003Cimg src=\u0022data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAYCAYAAACSuF9OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAHlklEQVRIiX2XyY8kRxXGf2+JyKyqruplZnq8zoA3MAYsNmFkIYwlLwgBAsRikBAc4ADiwJ\/AnRsHBOIMJ8TFgAQCgS3ZEptYjbEweLwNlsczvVR3V1dmxOOQNW0EiFBGZkoZyxffFy\/el3LuNXdElIoQRK0QFXOnlkIQqAiuhqmS3Fkuj6m1QgREIICIIAxFRBARILhaImJV68mTqIiAimDumAhNM8IjhIig1IIECFBKQRgGVtUBqCjUSlKlX02AyKodJ+1FAARVeXVyufouRC2IGhGv9jOEpIbWgl\/tIChBJQI0BNFhMkJQdUDoS8UQFCFEMdUVG8NCkOHb6lrdDHdjuewQgYhhgSKKrvqaKm5GUsVDFGpZETwwQgQSgqrhppgIJoqbIlGptVJrGQZwH1ZfK6p2IpWKELUSBOsbG+xcvgJUCEEcohZUBQLMlGRG8quABFCBumJLQERXMhiKYmZkS4ybBqLn8OiIxp0mOdkTtVZK6elLAWHYL7UCcO3ZbY7350AdSItANa9AKaaDxNkUF01EdEgYSEVPNqmgZgO1llBRVAwVZ9JM2Bytc2W+i4YSJWg8oZ4hCiFC33cDQwLnz53jn888i0ggAaaCEEBCJFaSKckU15Tpg1XE2NVYAdWBHTVMjexOtoRiiCSanHjtmTUODuccdx1nr9lmeXTIfG8fEyG7UqNy9\/3v4eknnmSWG4IYIgtQHURRBRFIpmQ3PDQhaSUXQg0wUVQNFcXNcTWyZ1yEZE6SRNKGra11PvLZj7G1ucHPv\/cjnrvwHNaskXyIpun6Gnff+x7+\/IvH2GhHQCEiBjAqqICZYDqw5i44uUF6p9ZY6QugiBpqjojh5qgm3GxVE\/e879089KVP8NSv\/8LDX\/8uicJt115H1Mr+wRzPxqe\/+hV+\/f0fcsNsxrJ01OiJKIN0uoquNOyhnBRTcGkn1K4gtQ7nUABiiDhqiWSOqpHMaVNm7M7nvvhRHvjwPcyv7PPDbz5M1hGb45abb7mOg91L7B4uuPfLnyKpUC88z+uv3WZ+dMiiX1JqT6kdaCW5YSa4K8mFlAyX8QxZ9lAqAcMeQRFJqBjiiaxOmxLjlHjoM\/fxwIfvAeAPj\/6JRMN0bcrauGH\/8hHn3\/5m7v\/A3Xjb8PjXvs326XU0Onb3gr5PlBgAhVRUg5QddyElxbPgMppC7qGAhEIogoI4aMLUSebklLjzztfywY+\/9yQl7L0059TZM1x\/fpvzd9zIjW+9icnpGRHBcz9+hMkoU+oabdOTmwpSqdHR90uidqiBamBu5MbxJDjTdegLETKAiSG6DMc1oTiyOgA\/84X3nZzMAA9+\/j7+s0QELzzyG5YvX+LMa05xvJvpDnaYaYdYRSyotaP2xwg9aoK5knLGmwbX6ZRUGPIMioeSMLI4OYysRkZ5653nuP76rf8C8O+llsLTP\/kV+089TTtR2vUxZ26\/gX53wt5FQWWJ0IFkoiRE6hBhybGcsWaETzemlAKsGDIED6cVo0VpMZoq3PXOW\/4vmPnLuzzxg8dYvvIyowZQ6I4OOXylw2XJeL2hdmU4ewxUErKSS92x3KLNCL9ma0TfB7VADUVDUYwUQsJoQ2mKcNtNp\/8nkKO9Q\/766J944bdPkqVj1NYhdVSIDuqxQaPkkRJJMYmVTAk1xVJGc4OkBvIIf+N2w+GiY3lcWPaVUiqlViQEiYoVwUQ4vTk+AXEwP+LCUy\/wzO\/\/zgt\/\/gdNdIy9EKngVLJWQgMsYDnkSklB8sBNMBM0JSS3kAxyhtyAt\/gHNl\/kYFGZzzv2DirzPtg\/hsMlLDpY9kLp4Vvf+A5HB0fsXNrj4PIeuRQShUSl1crIeiYpmLWV5bjCNEghtDbYDCkd6oFlw2rQdYYxpTs2tE3sXhnT0SL33HE6Zm1isRisklsmxKk4IYmCUzXTVwhR1BObm6fY29nFzWhSovGES2VrfQLHB0wznJkE124Wtk8bk4nw7MUd5kdHlNyxcd31\/OKnv+SZi8fM2sr29pTjLnj8iQNkbWMrNGVEDUsJb1pEDc8NnjKWGlSN3LSYJ971trdw8dIut95wltJVmmZE45mttTGH+wdMsjNrE9Ns7D1\/gTVZsDmBpD3JejYmPbfdOWbn4pyXL+4xHYFLz5m77uPwjz\/Db\/\/QJ2nWZvQV2skUTw2qjpiTPCFiCEPekRB8NuGmc7A1m7C7e0DfdUzHI3p3sAn7xx21KseLYFG3kFbJyWhTpVpl0VQ622DrdbAz\/ztpJDTe0185ZO0ND+AFY354BJZY7u8jcgDo4IViMOCDFwIplUsvVqRW6mIBtZDNkBJIBFYLicEbj1NmmpypO+tNYpwE18I4w3zR8Y43zXj+ilIv98xGMN15kVsffAt+5cLfWHYd6plaKt6M4NV\/CATwlFBVJIKogcYAQGtF+v7E4NfuGBdj56VnaXOLi7C+NuPUbAOPyuHhHpuzKb970vnnhREv7S545pUFoxw0uuT9\/fPI6Ztvj1oK\/XJJ7Y5JkykSQlku0NQM6aD2eG4BBs8NaA0UQeKqhx68uEYgVEwEV8EFlEo2QzXo+w6hsD111lvj8tFgcxuHu87DvwCrEznQnIJIIAAAAABJRU5ErkJggg==\u0022 data-src=\u0022https:\/\/avris.it\/image\/avris-container_big.png\u0022 alt=\u0022\u0022 class=\u0022border\u0022 width=\u0022900\u0022 height=\u0022600\u0022\u003E\u003C\/span\u003E\n                \n            \u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA dependency injection container with autowiring\u003C\/p\u003E\n\u003Ch3\u003EInstallation\u003C\/h3\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs bash border\u0022\u003Ecomposer require avris\/container\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch3\u003EUsage\u003C\/h3\u003E\n\u003Ch4\u003EBasics\u003C\/h4\u003E\n\u003Cp\u003EContainer resolves dependencies between defined services,\nin order to simplify the development process, avoid duplication of code,\nfacilitate interoperability and improve maintainability and testability.\nSee: \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Dependency_injection\u0022\u003EDependency Injection pattern\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E$parameterProvider = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E SimpleParameterProvider([\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027ROOT_DIR\u0027\u003C\/span\u003E =\u0026gt; \u003Cspan class=\u0022hljs-keyword\u0022\u003E__DIR__\u003C\/span\u003E]);\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ parameter provider is optional\u003C\/span\u003E\n\n$container = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E Container($parameterProvider);\n\n$container-\u0026gt;set(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027number\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-number\u0022\u003E4\u003C\/span\u003E);\n$container-\u0026gt;set(Foo::class, \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E Foo);\n$container-\u0026gt;setDefinition(Bar::class, [\n    \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027arguments\u0027\u003C\/span\u003E =\u0026gt; [\n        \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027$foo\u0027\u003C\/span\u003E =\u0026gt; \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027@\u0027\u003C\/span\u003E . Foo::class,\n        \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027$dir\u0027\u003C\/span\u003E =\u0026gt; \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027%ROOT_DIR%\/bar\u0027\u003C\/span\u003E,\n        \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027$number\u0027\u003C\/span\u003E =\u0026gt; \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027@number\u0027\u003C\/span\u003E,\n        \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027$float\u0027\u003C\/span\u003E =\u0026gt; \u003Cspan class=\u0022hljs-number\u0022\u003E69.123\u003C\/span\u003E,\n    ],\n    \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027public\u0027\u003C\/span\u003E =\u0026gt; \u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E,\n]);\n$container-\u0026gt;setDefinition(BarInterface::class, Bar::class); \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ alias\u003C\/span\u003E\n\n$container-\u0026gt;get(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027number\u0027\u003C\/span\u003E);              \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ 4\u003C\/span\u003E\n$container-\u0026gt;get(Foo::class);            \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ new Foo\u003C\/span\u003E\n$container-\u0026gt;get(BarInterface::class);   \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ new Bar(new Foo, __DIR__ . \u0027\/bar\u0027, 4, 69.123)\u003C\/span\u003E\n$container-\u0026gt;getParameter(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027ROOT_DIR\u0027\u003C\/span\u003E);   \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ __DIR__\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch4\u003EOptions\u003C\/h4\u003E\n\u003Cul\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Eclass\u003C\/code\u003E \u2013 the class of the service, will default to the service name if not given.\nIf the given class implements the \u003Ccode\u003EResolver\u003C\/code\u003E interface, it will be instantiated,\nand it\u2019s \u003Ccode\u003Eresolve\u003C\/code\u003E method executed to provide an actual value to be put in the container.\u003C\/p\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Earguments\u003C\/code\u003E \u2013 constructor arguments.\u003C\/p\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Ecalls\u003C\/code\u003E \u2013 method calls to be executed right after constructing the service (setter injection etc.)\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0027calls\u0027 =\u0026gt; [\n    [\u0027setLogger\u0027, [\u0027@logger\u0027]],\n    [\u0027registerListener\u0027, [\u0027@listenerA\u0027]],\n    [\u0027registerListener\u0027, [\u0027@listenerB\u0027]],\n],\u003C\/code\u003E\u003C\/pre\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Etags\u003C\/code\u003E \u2013 an array of string that help group similar services together; tagged services can be injected with \u003Ccode\u003E#tagName\u003C\/code\u003E:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E$container-\u0026gt;setDefinition(HandlerA::class, [\u0027tags\u0027 =\u0026gt; \u0027handler\u0027]);\n$container-\u0026gt;setDefinition(HandlerB::class, [\u0027tags\u0027 =\u0026gt; \u0027handler\u0027]);\n$container-\u0026gt;setDefinition(HandlerC::class, [\u0027tags\u0027 =\u0026gt; \u0027handler\u0027]);\n$container-\u0026gt;setDefinition(Manager::class, [\u0027arguments\u0027 =\u0026gt; [\u0027$handlers\u0027 =\u0026gt; \u0027#handler\u0027]]);\u003C\/code\u003E\u003C\/pre\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Efactory\u003C\/code\u003E -- determines if each \u003Ccode\u003Eget\u003C\/code\u003E should create a new service (\u003Ccode\u003Etrue\u003C\/code\u003E),\nor should one service be reused (\u003Ccode\u003Efalse\u003C\/code\u003E, default).\u003C\/p\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Eresolve\u003C\/code\u003E \u2013 instead of using \u003Ccode\u003Eclass\u003C\/code\u003E + \u003Ccode\u003Earguments\u003C\/code\u003E to construct the service,\nyou can use \u003Ccode\u003Eresolve\u003C\/code\u003E to define how it should be created:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E$container-\u0026gt;setDefinition(\u0027foo\u0027, [\u0027resolve\u0027 =\u0026gt; 4]); \/\/ 4\n$container-\u0026gt;setDefinition(\u0027language\u0027, [\u0027resolve\u0027 =\u0026gt; \u0027@Request.locale.language\u0027]); \/\/ $container-\u0026gt;get(\u0027Request\u0027)-\u0026gt;getLocale()-\u0026gt;getLanguage()\u003C\/code\u003E\u003C\/pre\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Epublic\u003C\/code\u003E \u2013 determines if the service should be accessible directly with \u003Ccode\u003Eget\u003C\/code\u003E,\nor can it only be injected into other services.\u003C\/p\u003E\n\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Ch4\u003EContainerCompiler: autowiring and autoconfiguration\u003C\/h4\u003E\n\u003Cp\u003EUsually it\u2019s obvious, which service should be injected into another.\nFor instance when your service has a constructor argument \u003Ccode\u003EPsr\\Cache\\CacheItemPoolInterface $cache\u003C\/code\u003E,\nand the container does have a service named \u003Ccode\u003EPsr\\Cache\\CacheItemPoolInterface\u003C\/code\u003E,\nthen explicitly writing \u003Ccode\u003E[\u0027arguments\u0027 =\u0026gt; [\u0027$cache\u0027 =\u0026gt; \u0027@Psr\\Cache\\CacheItemPoolInterface\u0027]\u003C\/code\u003E is redundant.\nYou can always specify the dependencies manually, then autowiring won\u0027t overwrite them.\u003C\/p\u003E\n\u003Cp\u003EAutowiring is not magic \u2013 it just follows simple rules to determine,\nwhich service should be injected into the constructor:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Eif the argument is a class which is defined in the container, use this service,\u003C\/li\u003E\n\u003Cli\u003Eif the argument is a class which is not defined in the container,\ntry to autowire that class and create a private service out of it,\u003C\/li\u003E\n\u003Cli\u003Eif the argument is an array and its name ends with \u003Ccode\u003Es\u003C\/code\u003E (e.g. \u003Ccode\u003Earray $helpers\u003C\/code\u003E),\ninject an array of services with a specific tag (\u003Ccode\u003E#helper\u003C\/code\u003E).\u003C\/li\u003E\n\u003Cli\u003Eif the argument is of type \u003Ccode\u003EBag\u003C\/code\u003E, inject the config value with its name\n(e.g. \u003Ccode\u003EBag $localisation\u003C\/code\u003E -\u0026gt; \u003Ccode\u003E@config.localisation\u003C\/code\u003E),\u003C\/li\u003E\n\u003Cli\u003Eif its name starts with \u003Ccode\u003Eenv\u003C\/code\u003E, inject a parameter:\n(e.g. \u003Ccode\u003Estring $envCacheDir\u003C\/code\u003E -\u0026gt; \u003Ccode\u003E%CACHE_DIR%\u003C\/code\u003E)\u003C\/li\u003E\n\u003Cli\u003Eif none of the above is true, but there is a default value, just use it,\u003C\/li\u003E\n\u003Cli\u003Eif none of the above is true, throw an exception \u2013 this argument should be defined explicitly.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EAutoconfiguration is another way to make your life simpler.\nFor instance, if you\u2019re using \u003Ca href=\u0022https:\/\/twig.symfony.com\/\u0022\u003ETwig\u003C\/a\u003E,\nyou might want all the classes in your code that extend \u003Ccode\u003ETwig\\Extension\\AbstractExtension\u003C\/code\u003E\nto be automatically registered as twig extension.\nAutoconfiguration lets you define what default config (tags, public etc.) should be added to them.\u003C\/p\u003E\n\u003Cp\u003ETo use autowiring and autoconfiguration, run the \u003Ccode\u003EContainerCompiler\u003C\/code\u003E:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E$container = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E Container;\n\n$services = [\n    \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027App\\\u0027 =\u0026gt; [\n        \u0027\u003C\/span\u003Edir\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027 =\u0026gt; \u0027\u003C\/span\u003E%MODULE_DIR%\/src\/\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027,\n        \u0027\u003C\/span\u003Eexclude\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027 =\u0026gt; [\u0027\u003C\/span\u003E\u003Cspan class=\u0022hljs-comment\u0022\u003E#^Entity\/#\u0027],\u003C\/span\u003E\n    ],\n\n    \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027App\\Foo\u0027\u003C\/span\u003E =\u0026gt; [\n        \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027arguments\u0027\u003C\/span\u003E =\u0026gt; [\n            \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027$bar\u0027\u003C\/span\u003E =\u0026gt; \u003Cspan class=\u0022hljs-number\u0022\u003E5\u003C\/span\u003E,\n        ],\n    ],\n\n    \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027App\\Bar\u0027\u003C\/span\u003E =\u0026gt; [\n        \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027public\u0027\u003C\/span\u003E =\u0026gt; \u003Cspan class=\u0022hljs-keyword\u0022\u003Etrue\u003C\/span\u003E,\n    ],\n];\n\n$autoconfiguration = [\n    \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027Twig\\Extension\\AbstractExtension\u0027\u003C\/span\u003E =\u0026gt; [\n        \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027tags\u0027\u003C\/span\u003E =\u0026gt; [\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027twigExtension\u0027\u003C\/span\u003E],\n    ],\n];\n\n$definitions = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E ContainerCompiler(\n    $container,\n    $services,\n    $autoconfiguration\n))-\u0026gt;compile();\n\n\u003Cspan class=\u0022hljs-comment\u0022\u003E\/** \u003Cspan class=\u0022hljs-doctag\u0022\u003E@var\u003C\/span\u003E ServiceDefinition $definition *\/\u003C\/span\u003E\n\u003Cspan class=\u0022hljs-keyword\u0022\u003Eforeach\u003C\/span\u003E ($definitions \u003Cspan class=\u0022hljs-keyword\u0022\u003Eas\u003C\/span\u003E $name =\u0026gt; $definition) {\n    \u003Cspan class=\u0022hljs-keyword\u0022\u003Eif\u003C\/span\u003E (!$container-\u0026gt;has($name)) {\n        $container-\u0026gt;setDefinition($name, $definition);\n    }\n}\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIn this example, the whole \u003Ccode\u003E%MODULE_DIR%\/src\/\u003C\/code\u003E except for (the \u003Ccode\u003E\/src\/Entity\u003C\/code\u003E dir) will be scanned for PHP files\nand all the found classes will be autowired as private services. If some of them are not used and not public,\nthey will be removed from the container.\u003C\/p\u003E\n\u003Cp\u003ECompiling the container has \u003Cstrong\u003Eno impact on performance\u003C\/strong\u003E on production environment,\nas long as you \u003Cstrong\u003Ecache the result of \u003Ccode\u003Ecompile()\u003C\/code\u003E\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Ch4\u003EServiceLocator\u003C\/h4\u003E\n\u003Cp\u003EService locator restricts access to services in the container only to a selected list of names:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022hljs php border\u0022\u003E$container = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E Container();\n$container-\u0026gt;set(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027foo\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027abc\u0027\u003C\/span\u003E);\n$container-\u0026gt;set(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027bar\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027def\u0027\u003C\/span\u003E);\n$container-\u0026gt;set(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027secret\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027XYZ\u0027\u003C\/span\u003E);\n\n$locator = \u003Cspan class=\u0022hljs-keyword\u0022\u003Enew\u003C\/span\u003E ServiceLocator($container, [\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027foo\u0027\u003C\/span\u003E, \u003Cspan class=\u0022hljs-string\u0022\u003E\u0027bar\u0027\u003C\/span\u003E]);\n\n$locator-\u0026gt;get(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027foo\u0027\u003C\/span\u003E);     \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ \u0027abc\u0027\u003C\/span\u003E\n$locator-\u0026gt;get(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027bar\u0027\u003C\/span\u003E);     \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ \u0027def\u0027\u003C\/span\u003E\n$locator-\u0026gt;get(\u003Cspan class=\u0022hljs-string\u0022\u003E\u0027secret\u0027\u003C\/span\u003E);  \u003Cspan class=\u0022hljs-comment\u0022\u003E\/\/ Exception\u003C\/span\u003E\n\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch3\u003EContainerAssistedBuilder\u003C\/h3\u003E\n\u003Cp\u003E\u003Ccode\u003EContainerAssistedBuilder\u003C\/code\u003E can be used to join together a couple of \u003Ccode\u003EContainerBuilderExtension\u003C\/code\u003Es\nwhich encapsulate a set of service definitions that form a library together.\nFor an example, see \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Localisator\u0022\u003EAvris Localisator\u003C\/a\u003E.\u003C\/p\u003E\n\u003Ch4\u003EMicrus\u003C\/h4\u003E\n\u003Cp\u003EThis container was originally built as a part of the \u003Ca href=\u0022https:\/\/micrus.avris.it\u0022\u003EMicrus framework\u003C\/a\u003E.\u003C\/p\u003E\u003Csvg xmlns=\u0022http:\/\/www.w3.org\/2000\/svg\u0022 style=\u0022display: none;\u0022\u003E\u003C\/svg\u003E","tags":["autoconfiguration","autowiring","container","dependencies","dependency injection","library","php","programming"],"hasMore":true,"image":"https:\/\/avris.it\/image\/avris-container_small.png","introLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-container_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-container_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA dependency injection container with autowiring\u003C\/p\u003E","contentLite":"\u003Cfigure\u003E\u003Ca href=\u0022https:\/\/avris.it\/image\/avris-container_big.png\u0022 target=\u0022_blank\u0022 rel=\u0022noopener\u0022\u003E\u003Cimg src=\u0022https:\/\/avris.it\/image\/avris-container_mini.png\u0022 alt=\u0022\u0022 width=\u0022240\u0022 height=\u0022160\u0022 loading=\u0022lazy\u0022\u003E\u003C\/a\u003E\u003C\/figure\u003E\u003C\/p\u003E\n\u003Cp\u003EA dependency injection container with autowiring\u003C\/p\u003E\n\u003Ch3\u003EInstallation\u003C\/h3\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-bash\u0022\u003Ecomposer require avris\/container\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch3\u003EUsage\u003C\/h3\u003E\n\u003Ch4\u003EBasics\u003C\/h4\u003E\n\u003Cp\u003EContainer resolves dependencies between defined services,\nin order to simplify the development process, avoid duplication of code,\nfacilitate interoperability and improve maintainability and testability.\nSee: \u003Ca href=\u0022https:\/\/en.wikipedia.org\/wiki\/Dependency_injection\u0022\u003EDependency Injection pattern\u003C\/a\u003E.\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003E$parameterProvider = new SimpleParameterProvider([\u0027ROOT_DIR\u0027 =\u0026gt; __DIR__]);\n\/\/ parameter provider is optional\n\n$container = new Container($parameterProvider);\n\n$container-\u0026gt;set(\u0027number\u0027, 4);\n$container-\u0026gt;set(Foo::class, new Foo);\n$container-\u0026gt;setDefinition(Bar::class, [\n    \u0027arguments\u0027 =\u0026gt; [\n        \u0027$foo\u0027 =\u0026gt; \u0027@\u0027 . Foo::class,\n        \u0027$dir\u0027 =\u0026gt; \u0027%ROOT_DIR%\/bar\u0027,\n        \u0027$number\u0027 =\u0026gt; \u0027@number\u0027,\n        \u0027$float\u0027 =\u0026gt; 69.123,\n    ],\n    \u0027public\u0027 =\u0026gt; true,\n]);\n$container-\u0026gt;setDefinition(BarInterface::class, Bar::class); \/\/ alias\n\n$container-\u0026gt;get(\u0027number\u0027);              \/\/ 4\n$container-\u0026gt;get(Foo::class);            \/\/ new Foo\n$container-\u0026gt;get(BarInterface::class);   \/\/ new Bar(new Foo, __DIR__ . \u0027\/bar\u0027, 4, 69.123)\n$container-\u0026gt;getParameter(\u0027ROOT_DIR\u0027);   \/\/ __DIR__\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch4\u003EOptions\u003C\/h4\u003E\n\u003Cul\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Eclass\u003C\/code\u003E \u2013 the class of the service, will default to the service name if not given.\nIf the given class implements the \u003Ccode\u003EResolver\u003C\/code\u003E interface, it will be instantiated,\nand it\u2019s \u003Ccode\u003Eresolve\u003C\/code\u003E method executed to provide an actual value to be put in the container.\u003C\/p\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Earguments\u003C\/code\u003E \u2013 constructor arguments.\u003C\/p\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Ecalls\u003C\/code\u003E \u2013 method calls to be executed right after constructing the service (setter injection etc.)\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0027calls\u0027 =\u0026gt; [\n    [\u0027setLogger\u0027, [\u0027@logger\u0027]],\n    [\u0027registerListener\u0027, [\u0027@listenerA\u0027]],\n    [\u0027registerListener\u0027, [\u0027@listenerB\u0027]],\n],\u003C\/code\u003E\u003C\/pre\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Etags\u003C\/code\u003E \u2013 an array of string that help group similar services together; tagged services can be injected with \u003Ccode\u003E#tagName\u003C\/code\u003E:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E$container-\u0026gt;setDefinition(HandlerA::class, [\u0027tags\u0027 =\u0026gt; \u0027handler\u0027]);\n$container-\u0026gt;setDefinition(HandlerB::class, [\u0027tags\u0027 =\u0026gt; \u0027handler\u0027]);\n$container-\u0026gt;setDefinition(HandlerC::class, [\u0027tags\u0027 =\u0026gt; \u0027handler\u0027]);\n$container-\u0026gt;setDefinition(Manager::class, [\u0027arguments\u0027 =\u0026gt; [\u0027$handlers\u0027 =\u0026gt; \u0027#handler\u0027]]);\u003C\/code\u003E\u003C\/pre\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Efactory\u003C\/code\u003E -- determines if each \u003Ccode\u003Eget\u003C\/code\u003E should create a new service (\u003Ccode\u003Etrue\u003C\/code\u003E),\nor should one service be reused (\u003Ccode\u003Efalse\u003C\/code\u003E, default).\u003C\/p\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Eresolve\u003C\/code\u003E \u2013 instead of using \u003Ccode\u003Eclass\u003C\/code\u003E + \u003Ccode\u003Earguments\u003C\/code\u003E to construct the service,\nyou can use \u003Ccode\u003Eresolve\u003C\/code\u003E to define how it should be created:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E$container-\u0026gt;setDefinition(\u0027foo\u0027, [\u0027resolve\u0027 =\u0026gt; 4]); \/\/ 4\n$container-\u0026gt;setDefinition(\u0027language\u0027, [\u0027resolve\u0027 =\u0026gt; \u0027@Request.locale.language\u0027]); \/\/ $container-\u0026gt;get(\u0027Request\u0027)-\u0026gt;getLocale()-\u0026gt;getLanguage()\u003C\/code\u003E\u003C\/pre\u003E\n\u003C\/li\u003E\n\u003Cli\u003E\n\u003Cp\u003E\u003Ccode\u003Epublic\u003C\/code\u003E \u2013 determines if the service should be accessible directly with \u003Ccode\u003Eget\u003C\/code\u003E,\nor can it only be injected into other services.\u003C\/p\u003E\n\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Ch4\u003EContainerCompiler: autowiring and autoconfiguration\u003C\/h4\u003E\n\u003Cp\u003EUsually it\u2019s obvious, which service should be injected into another.\nFor instance when your service has a constructor argument \u003Ccode\u003EPsr\\Cache\\CacheItemPoolInterface $cache\u003C\/code\u003E,\nand the container does have a service named \u003Ccode\u003EPsr\\Cache\\CacheItemPoolInterface\u003C\/code\u003E,\nthen explicitly writing \u003Ccode\u003E[\u0027arguments\u0027 =\u0026gt; [\u0027$cache\u0027 =\u0026gt; \u0027@Psr\\Cache\\CacheItemPoolInterface\u0027]\u003C\/code\u003E is redundant.\nYou can always specify the dependencies manually, then autowiring won\u0027t overwrite them.\u003C\/p\u003E\n\u003Cp\u003EAutowiring is not magic \u2013 it just follows simple rules to determine,\nwhich service should be injected into the constructor:\u003C\/p\u003E\n\u003Cul\u003E\n\u003Cli\u003Eif the argument is a class which is defined in the container, use this service,\u003C\/li\u003E\n\u003Cli\u003Eif the argument is a class which is not defined in the container,\ntry to autowire that class and create a private service out of it,\u003C\/li\u003E\n\u003Cli\u003Eif the argument is an array and its name ends with \u003Ccode\u003Es\u003C\/code\u003E (e.g. \u003Ccode\u003Earray $helpers\u003C\/code\u003E),\ninject an array of services with a specific tag (\u003Ccode\u003E#helper\u003C\/code\u003E).\u003C\/li\u003E\n\u003Cli\u003Eif the argument is of type \u003Ccode\u003EBag\u003C\/code\u003E, inject the config value with its name\n(e.g. \u003Ccode\u003EBag $localisation\u003C\/code\u003E -\u0026gt; \u003Ccode\u003E@config.localisation\u003C\/code\u003E),\u003C\/li\u003E\n\u003Cli\u003Eif its name starts with \u003Ccode\u003Eenv\u003C\/code\u003E, inject a parameter:\n(e.g. \u003Ccode\u003Estring $envCacheDir\u003C\/code\u003E -\u0026gt; \u003Ccode\u003E%CACHE_DIR%\u003C\/code\u003E)\u003C\/li\u003E\n\u003Cli\u003Eif none of the above is true, but there is a default value, just use it,\u003C\/li\u003E\n\u003Cli\u003Eif none of the above is true, throw an exception \u2013 this argument should be defined explicitly.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cp\u003EAutoconfiguration is another way to make your life simpler.\nFor instance, if you\u2019re using \u003Ca href=\u0022https:\/\/twig.symfony.com\/\u0022\u003ETwig\u003C\/a\u003E,\nyou might want all the classes in your code that extend \u003Ccode\u003ETwig\\Extension\\AbstractExtension\u003C\/code\u003E\nto be automatically registered as twig extension.\nAutoconfiguration lets you define what default config (tags, public etc.) should be added to them.\u003C\/p\u003E\n\u003Cp\u003ETo use autowiring and autoconfiguration, run the \u003Ccode\u003EContainerCompiler\u003C\/code\u003E:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003E$container = new Container;\n\n$services = [\n    \u0027App\\\u0027 =\u0026gt; [\n        \u0027dir\u0027 =\u0026gt; \u0027%MODULE_DIR%\/src\/\u0027,\n        \u0027exclude\u0027 =\u0026gt; [\u0027#^Entity\/#\u0027],\n    ],\n\n    \u0027App\\Foo\u0027 =\u0026gt; [\n        \u0027arguments\u0027 =\u0026gt; [\n            \u0027$bar\u0027 =\u0026gt; 5,\n        ],\n    ],\n\n    \u0027App\\Bar\u0027 =\u0026gt; [\n        \u0027public\u0027 =\u0026gt; true,\n    ],\n];\n\n$autoconfiguration = [\n    \u0027Twig\\Extension\\AbstractExtension\u0027 =\u0026gt; [\n        \u0027tags\u0027 =\u0026gt; [\u0027twigExtension\u0027],\n    ],\n];\n\n$definitions = new ContainerCompiler(\n    $container,\n    $services,\n    $autoconfiguration\n))-\u0026gt;compile();\n\n\/** @var ServiceDefinition $definition *\/\nforeach ($definitions as $name =\u0026gt; $definition) {\n    if (!$container-\u0026gt;has($name)) {\n        $container-\u0026gt;setDefinition($name, $definition);\n    }\n}\u003C\/code\u003E\u003C\/pre\u003E\n\u003Cp\u003EIn this example, the whole \u003Ccode\u003E%MODULE_DIR%\/src\/\u003C\/code\u003E except for (the \u003Ccode\u003E\/src\/Entity\u003C\/code\u003E dir) will be scanned for PHP files\nand all the found classes will be autowired as private services. If some of them are not used and not public,\nthey will be removed from the container.\u003C\/p\u003E\n\u003Cp\u003ECompiling the container has \u003Cstrong\u003Eno impact on performance\u003C\/strong\u003E on production environment,\nas long as you \u003Cstrong\u003Ecache the result of \u003Ccode\u003Ecompile()\u003C\/code\u003E\u003C\/strong\u003E.\u003C\/p\u003E\n\u003Ch4\u003EServiceLocator\u003C\/h4\u003E\n\u003Cp\u003EService locator restricts access to services in the container only to a selected list of names:\u003C\/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-php\u0022\u003E$container = new Container();\n$container-\u0026gt;set(\u0027foo\u0027, \u0027abc\u0027);\n$container-\u0026gt;set(\u0027bar\u0027, \u0027def\u0027);\n$container-\u0026gt;set(\u0027secret\u0027, \u0027XYZ\u0027);\n\n$locator = new ServiceLocator($container, [\u0027foo\u0027, \u0027bar\u0027]);\n\n$locator-\u0026gt;get(\u0027foo\u0027);     \/\/ \u0027abc\u0027\n$locator-\u0026gt;get(\u0027bar\u0027);     \/\/ \u0027def\u0027\n$locator-\u0026gt;get(\u0027secret\u0027);  \/\/ Exception\u003C\/code\u003E\u003C\/pre\u003E\n\u003Ch3\u003EContainerAssistedBuilder\u003C\/h3\u003E\n\u003Cp\u003E\u003Ccode\u003EContainerAssistedBuilder\u003C\/code\u003E can be used to join together a couple of \u003Ccode\u003EContainerBuilderExtension\u003C\/code\u003Es\nwhich encapsulate a set of service definitions that form a library together.\nFor an example, see \u003Ca href=\u0022https:\/\/gitlab.com\/Avris\/Localisator\u0022\u003EAvris Localisator\u003C\/a\u003E.\u003C\/p\u003E\n\u003Ch4\u003EMicrus\u003C\/h4\u003E\n\u003Cp\u003EThis container was originally built as a part of the \u003Ca href=\u0022https:\/\/micrus.avris.it\u0022\u003EMicrus framework\u003C\/a\u003E.\u003C\/p\u003E","words":868,"readTime":4,"lang":"en"}}}}}