{
    "href": "/post/2013/12/02/quicker-easier-more-seductive-the-difference-between-factories-registries-and-service-locators/",
    "relId": "2013/12/02/quicker-easier-more-seductive-the-difference-between-factories-registries-and-service-locators",
    "title": "Quicker, Easier, More Seductive: The Difference Between Factories, Registries, and Service Locators",
    "author": "pmjones",
    "markup": "html",
    "tags": [
        {
            "href": "/tag/aura/",
            "relId": "aura",
            "title": "Aura",
            "author": null,
            "created": "2020-09-14 21:51:57 UTC",
            "updated": [
                "2020-09-14 21:51:57 UTC"
            ],
            "markup": "markdown"
        },
        {
            "href": "/tag/php/",
            "relId": "php",
            "title": "PHP",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/programming/",
            "relId": "programming",
            "title": "Programming",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        }
    ],
    "created": "2013-12-02 17:35:01 UTC",
    "updated": [
        "2013-12-02 17:35:01 UTC"
    ],
    "html": "<p>In <a href=\"http://paul-m-jones.com/archives/4792\">last week\u2019s episode</a> of this unexpected series, I said, \u201cGo ahead and use Service Locator, but make sure each Locator contains only one type of object. This condition of restraint will keep a single locator from becoming a menace.\u201d  (I recommend \u201creal\u201d dependency injection containers as the preferred inversion-of-control mechanism; try the <a href=\"https://github.com/auraphp/Aura.Di\">Aura.Di</a> container.)</p>\n<p>The \u201conly one type of object\u201d constraint generated some discussion regarding factories and registries.  On Reddit, <a href=\"http://www.reddit.com/r/PHP/comments/1rf6xz/quicker_easier_more_seductive_restraining_your/cdmmken\">teresko commented</a>:</p>\n<blockquote>\n<p>I don\u2019t think I have ever seen a use of Service Locator where it adhered to this rule. Hell \u2026 I am not even sure that you can call it \u201cService Locator\u201d then, because it is just a smarter sounding name for Registry pattern.</p>\n<p>When you apply this rule, what you get instead is a factory, which enforces uniqueness of an instances, that it creates.</p>\n</blockquote>\n<p>On the blog itself, <a href=\"http://paul-m-jones.com/archives/4792/comment-page-1#comment-445594\">Adrian Mu asked</a>:</p>\n<blockquote>\n<p>In the case of the Aura\u00e2\u0080\u0099s filter package am I wrong to interpret the \u00e2\u0080\u009crule service locator\u00e2\u0080\u009d as a \u00e2\u0080\u009crule factory\u00e2\u0080\u009d? If no, what is the difference between a factory and a service locator as you describe it? If yes, where?</p>\n</blockquote>\n<p>And on Twitter, <a href=\"https://twitter.com/taylorotwell/status/406836896711467008\">Taylor Otwell asked a similar question</a>:</p>\n<blockquote>\n<p>that \u201cone type\u201d of service locator is just a \u201cfactory\u201d, right?</p>\n</blockquote>\n<p>The differences between factories, registries, and containers (both service locators and dependency injection containers) can be subtle and hard to grasp at first. Here\u2019s how I keep them straight:</p>\n<ul>\n<li>\n<p>a Factory creates and returns an object, but does not retain the created object for future use;</p>\n</li>\n<li>\n<p>a Registry retains an object instance by name for repeated use, but does not create that object;</p>\n</li>\n<li>\n<p>a Service Locator contains a named object (a \u201cservice\u201d) and creates it if it<br>\nhas a definition for that service; the creation logic might itself be a Factory, and the retention logic might itself be a Registry.</p>\n</li>\n</ul>\n<p>By way of example, I have put together an <a href=\"https://github.com/pmjones/Pmjones/blob/master/service-locator.php\">example service locator implementation</a> along with an embedded test case.  It has only two methods: <code>set()</code> and <code>get()</code>:</p>\n<ul>\n<li>\n<p>The <code>set()</code> method takes an <em>object name</em> as its first argument, and<br>\na <em>factory</em> (in this case, a <a href=\"http://php.net/manual/en/language.types.callable.php\">callable</a>). The factories are retained in a <em>registry</em> (in this case, a plain-old PHP array).</p>\n</li>\n<li id=\"scroll_to_here\">\n<p>The <code>get()</code> method looks in a <em>registry</em> of instances for the requested object by name and returns it. If the object is not there, it uses the <em>factory</em> for that object name and retains it in the instance <em>registry</em>.</p>\n</li>\n</ul>\n<p>Here\u2019s an example use:</p>\n<pre><code>&lt;?php\n// create the service locator\n$locator = new PmjonesServiceLocator;\n\n// add a factory; this can be any callable, whether\n// a closure, an object with an __invoke() method,\n// a function name, a static class method, an object\n// instance and method name, etc.\n$locator-&gt;set('my_object', function () {\n    return new VendorPackageClassName;\n});\n\n// get back an object instance; the locator\n// will create and retain it the first time\n$one = $locator-&gt;get('my_object');\n\n// the next and subsequent times, the locator\n// return the same instance\n$two = $locator-&gt;get('my_object');\nvar_dump($one === $two); // true\n?&gt;\n</code></pre>\n<p>That should help illustrate the difference between a factory, a registry, and a service locator.</p>\n<p>Again, I must stress: Service locators can easily get out of control. If you <em>can</em> avoid using a service locator, you <em>should</em>. Instead of service locators, use dependency injection proper as much as possible, even though it is more work up front. If you <em>must</em> use a service locator: place only one type of object in it, use multiple locators if necessary, and <em>inject</em> each locator instead of using static calls for access.</p>\n<h3>Afterword</h3>\n<p>In <a href=\"http://auraphp.com\">Aura</a>,  we use dependency injection everywhere, all the time.  In the rare cases that a service locator makes sense, that locator follows the \u201conly one type of object\u201d rule, and the locator itself is injected via the DI container. This makes the codebase very clean and a lot easier to test.</p>\n<p>If you like clean code, fully decoupled libraries, and truly independent packages, then <a href=\"http://auraphp.com\">the Aura project</a> is for you. Download a single package and start using it in your project today, with no added dependencies.</p>\n<hr>\n<p class=\"reddit-links\">Read the Reddit discussion about this post <a href=\"https://www.reddit.com/r/PHP/comments/1rx3uq/quicker_easier_more_seductive_the_difference/\">here</a>.</p>\n"
}
