{
    "href": "/post/2019/12/09/controllers-are-services/",
    "relId": "2019/12/09/controllers-are-services",
    "title": "Controllers are Services",
    "author": "pmjones",
    "created": "2019-12-09 14:07:04 UTC",
    "updated": [
        "2019-12-09 14:07:04 UTC",
        "2019-12-09 16:10:01 UTC",
        "2019-12-09 20:44:50 UTC",
        "2019-12-09 20:46:26 UTC",
        "2019-12-09 20:50:01 UTC",
        "2020-10-29 21:50:57 UTC"
    ],
    "tags": [
        {
            "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"
        }
    ],
    "markup": "markdown",
    "html": "<p>tl;dr: Contra <a href=\"/post/2019/12/05/controllers-are-not-services/\">my previous opinion</a>,\ncontrollers <em>are</em> Service objects; my understanding of a \"Service\", regarding\nDI/SL Containers, was incorrect. However, I do continue to opine that it is\nbetter use a Factory to get new Controller instances, rather than getting them\nfrom the Container directly in a non-Factory object. All that and more in this\nfollowup post.</p>\n<hr>\n<h2>I</h2>\n<p><a href=\"/post/2019/12/05/controllers-are-not-services/\">My previous post</a> generated\n<a href=\"https://www.reddit.com/r/PHP/comments/e6l1wp/controllers_are_not_services/f9tszby/\">a great discussion on Reddit</a>\nbetween myself and\n<a href=\"https://www.reddit.com/user/ahundiak\">/u/ahundiak</a>, which I suggest you read\nin its entirety. To summarize:</p>\n<ul>\n<li>\n<p>I thought of Services in a Container as objects that are retained for reuse\nthroughout the application; e.g. a PDO instance, a logger, etc.</p>\n</li>\n<li>\n<p>ahundiak disagreed, and pointed to the Symfony explanation of a Service as\n\"objects that do something\", even when not shared throughout the system.</p>\n</li>\n<li>\n<p>I found that explanation unsatisfying and not well-defined.</p>\n</li>\n<li>\n<p>However, ahundiak also said \"Symfony only creates service definitions for\nobjects which are actually injected somewhere.\" That piqued my interest,\nbecause it got closer to the heart what I was trying to express.</p>\n</li>\n</ul>\n<p>From there we ventured a bit further afield.</p>\n\n<a id=\"more\"</a>\n\n<h2>II</h2>\n<p>Based on that conversation, I did a couple hours' of research, using variations\non \"what is a service object\" (and you get some unexpected search results in a\ncouple of cases). In the end, though, I found myself at the Misko Hevery article\n<a href=\"http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/\">To <code>new</code> or not to <code>new</code>.</a></p>\n<p>I have taken Misko's advice before, particularly from his article on\n<a href=\"http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/\">How to Think About the \u00e2\u0080\u009cnew\u00e2\u0080\u009d Operator with Respect to Unit Testing</a>;\nI believe I refer to it in <a href=\"https://leanpub.com/mlaphp\">MLAPHP</a>. In that\narticle, his final summary point is that your classes should <em>either</em> have\napplication logic in them, <em>or</em> have <code>new</code> operators, but not both.</p>\n<p>The idea is that object <em>construction</em> is a concern to be separated from object\n<em>use</em>. The end result is that you put all object construction into Factories,\nand anything that needs to create an object uses the Factory instead of the\n<code>new</code> operator.</p>\n<p>In his later article on \"To <code>new</code> or not\", Misko lays out definitions around\ntwo distinct groups of objects within any application. Lightly edited for\ncomprehension and emphasis, he says:</p>\n<blockquote>\n<ul>\n<li>\n<p>\"Injectables\" are objects which you will ask for in the constructors and\nexpect the DI framework to supply. ... All external services are Injectables.\n... Sometimes I refer to Injectables as Service Objects, but that term is\noverloaded.</p>\n</li>\n<li>\n<p>There are a lot of objects out there which DI framework will never be able\nto supply. Let's call these \u00e2\u0080\u009cNewables\u00e2\u0080\u009d since you will be forced to call\n<code>new</code> on them manually. ... <strong>Newables are objects which are at\nthe end of your application object graph.</strong> ... Sometimes I refer to\nNewables as Value Object, but again, the term is overloaded.</p>\n</li>\n<li>\n<p>It is OK for Newable to know about Injectable. What is not OK is for the\nNewable to have a field reference to Injectable.</p>\n</li>\n</ul>\n</blockquote>\n<p>Now <em>that</em> is something I can wrap my head around. To a first approximation,\nNewables/Values are leafs on the object graph; everything else on the path to a\nNewable/Value is an Injectable/Service.</p>\n<p>I think that very nicely backs up ahundiak's reference to Symfony's explanation\nabout Service objects, with some additional and welcome rigor.</p>\n<p>Misko goes on to define some rules-of-thumb around Injectables/Services and\nNewables/Values. Paraphrasing and summarizing:</p>\n<blockquote>\n<ul>\n<li>\n<p>An Injectable can ask for primitives (int, float, string, etc.) and other\nInjectables in its constructor, but <em>never</em> a Newable.</p>\n</li>\n<li>\n<p>Conversely, a Newable can ask for primitives and other Newables in its\nconstructor, but <em>never</em> an Injectable.</p>\n</li>\n</ul>\n</blockquote>\n<h2>III</h2>\n<p>Based on Misko's definition (which is obviously better than my prior one)\nControllers <em>are</em> Services that a DI container can provide. Mea culpa.</p>\n<p>However, I continue to stand by a corollary opinion I expressed in the previous\narticle: that you should not retain a Controller instance for reuse inside the\nContainer. Instead, you should use a Factory to create the Controller instance.\nFurther (and I did not say this explicitly) you should typehint on that\nFactory instead of the Container itself.</p>\n<p>Now, it is well within the proper scope of a Container to be used as a Factory.\nA Container plays two roles: that of Factory (to create new object instances)\nand of Registry (to retain already-created instances for shared use). So in a\nDispatcher, for example, you could do this to run a Controller based on Route\ninformation:</p>\n<pre><code class=\"language-php\">class Dispatcher\n{\n    protected $container;\n\n    public function __construct(Container $container)\n    {\n        $this-&gt;container = $container;\n    }\n\n    public function dispatch(Route $route)\n    {\n        $class = 'App\\Http\\Controller\\\\' . $route-&gt;getController();\n        $object = $this-&gt;container-&gt;new($class);\n        $method = $route-&gt;getAction();\n        $params = $route-&gt;getParams();\n        return $object-&gt;$method(...$params);\n    }\n}\n</code></pre>\n<p>That's not bad -- by calling <code>new()</code> on the Container, you can tell the\nContainer is being used as a Factory, not a Registry. (Some Containers will\nallow you to configure certain types always to be new instances, so that calling\n<code>get()</code> will always return a new instance, but I am not a fan of that idiom.)</p>\n<h2>IV</h2>\n<p>However, if you you consider\n<a href=\"/post/2018/01/02/considering-typehints-as-communication/\">typehints as communication</a>,\nthen typehinting on <code>Container</code> communicates \"the Dispatcher will need to create\nor locate anything the Container can provide.\" It's using the Container as a\nService Locator, and in general we ought to prefer Dependency Injection.</p>\n<p>As an alternative, we might typehint on a <code>ControllerFactory</code> instead. That kind\nof typehint communicates a narrower requirement: \"the Dispatcher will need to\ncreate new Controller instances.\"</p>\n<p>Putting together a ControllerFactory is easy enough ...</p>\n<pre><code class=\"language-php\">class ControllerFactory\n{\n    protected $container;\n\n    public function __construct(Container $container)\n    {\n        $this-&gt;container = $container;\n    }\n\n    public function new(string $suffix) : Controller\n    {\n        $class = 'App\\Http\\Controller\\\\' . $suffix;\n        return $this-&gt;container-&gt;new($class);\n    }\n}\n</code></pre>\n<p>... and then the Dispatcher can depend on that, instead of the Container:</p>\n<pre><code class=\"language-php\">class Dispatcher\n{\n    protected $controllerFactory;\n\n    public function __construct(ControllerFactory $controllerFactory)\n    {\n        $this-&gt;controllerFactory = $controllerFactory;\n    }\n\n    public function dispatch(Route $route)\n    {\n        $object = $this-&gt;controllerFactory-&gt;new($route-&gt;getController());\n        $method = $route-&gt;getAction();\n        $params = $route-&gt;getParams();\n        return $object-&gt;$method(...$params);\n    }\n}\n</code></pre>\n<p>Of course, the ControllerFactory itself now depends the Container -- the\ndependency on the Container just moved, it didn't disappear. Even so, this\narrangement is less objectionable for a couple of reasons:</p>\n<ul>\n<li>\n<p>The \"creation of objects\" concern remains separated, per\n<a href=\"http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/\">Hevery's guideline</a>\n\"to have either classes with logic OR classes with <code>new</code> operators.\"</p>\n</li>\n<li>\n<p>The Controller instances being created really are likely to need a wide range\nof many different object injections, including shared objects from the\nContainer. The typehint of <code>Container</code> is an accurate communication here.</p>\n</li>\n</ul>\n<h2>V</h2>\n<p>As often happens, the answer leads to more questions. In this case, I begin to wonder\nabout the kinds of objects that belong in a Container, per Misko's definitions.\nFor example, is an HTTP Request object something that ought to be created and\nretained within a Container? I can think of no Request implementations that\ndepend on Injectables; it seems more like a Newable, per Misko, in that it\nexists as a leaf on the object graph.</p>\n<p>Well, I will leave that for another day. Many thanks to ahundiak for correcting\nme, or least leading me to correction, on this topic.</p>\n<hr>\n<p>See the Reddit conversation on this post <a href=\"https://www.reddit.com/r/PHP/comments/e8adzi/controllers_are_services/\">here</a>.</p>\n"
}
