<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Anton Ukhanev</title>
    <description>The latest articles on Forem by Anton Ukhanev (@xedinunknown).</description>
    <link>https://forem.com/xedinunknown</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F35491%2F106ffc63-d958-405f-95cd-72db8a3d2bea.png</url>
      <title>Forem: Anton Ukhanev</title>
      <link>https://forem.com/xedinunknown</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/xedinunknown"/>
    <language>en</language>
    <item>
      <title>PHP Array: A Gross Mistake</title>
      <dc:creator>Anton Ukhanev</dc:creator>
      <pubDate>Mon, 02 May 2022 11:51:23 +0000</pubDate>
      <link>https://forem.com/xedinunknown/php-array-a-gross-mistake-3np4</link>
      <guid>https://forem.com/xedinunknown/php-array-a-gross-mistake-3np4</guid>
      <description>&lt;p&gt;Any developer who has spent a little time working with PHP knows one of the most used compound &lt;a href="https://www.php.net/manual/en/language.types.intro.php" rel="noopener noreferrer"&gt;types&lt;/a&gt; - the &lt;a href="https://www.php.net/manual/en/language.types.array.php" rel="noopener noreferrer"&gt;array&lt;/a&gt;. Its uses reach from de-serialization results, to the backbone of sets, collections and containers, stacks and queues, indexes, and much more. It is so ubiquitous that it's possible to make an object appear to be an array with the &lt;a href="https://www.php.net/manual/en/class.arrayaccess.php" rel="noopener noreferrer"&gt;&lt;code&gt;ArrayAccess&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.php.net/manual/en/class.iterator.php" rel="noopener noreferrer"&gt;&lt;code&gt;Iterator&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://www.php.net/manual/en/class.countable.php" rel="noopener noreferrer"&gt;&lt;code&gt;Countable&lt;/code&gt;&lt;/a&gt; interfaces.&lt;/p&gt;

&lt;p&gt;However, countless examples suggest that even experienced PHP developers frequently make the same kind of mistake, which often has a hidden cost months or even years later. I contend that&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An array is not an array.&lt;/li&gt;
&lt;li&gt;What you really want is &lt;em&gt;either a map or a list&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;You're doing it wrong.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1415951528658153477-691" src="https://platform.twitter.com/embed/Tweet.html?id=1415951528658153477"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1415951528658153477-691');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1415951528658153477&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h2&gt;
  
  
  PHP Array
&lt;/h2&gt;

&lt;p&gt;From &lt;a href="https://www.javatpoint.com/array-in-java" rel="noopener noreferrer"&gt;Java&lt;/a&gt; to &lt;a href="https://www.cpp.edu/~elab/ECE114/Array.html" rel="noopener noreferrer"&gt;C++&lt;/a&gt; to &lt;a href="https://www.freepascal.org/doc0s-html/ref/refsu14.html" rel="noopener noreferrer"&gt;Pascal&lt;/a&gt; to &lt;a href="https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/arrays/" rel="noopener noreferrer"&gt;Basic&lt;/a&gt;, an array is an implementation of a &lt;a href="https://en.wikipedia.org/wiki/List_(abstract_data_type)" rel="noopener noreferrer"&gt;list&lt;/a&gt;. As follows from official documentation, however, a PHP array is really a linked hash map. This is very versatile and flexible; yet it goes against the very &lt;a href="https://dev.to/xedinunknown/separation-of-concerns-3e7d"&gt;principles that keep our code sane&lt;/a&gt;. Specifically, it violates the Interface Segregation Principle, which leads to much lower separation of concerns, puts unnecessary burden on implementations, confuses and complicates consumers, and makes implementations less flexible. All this leads to a cascade of more negative side-effects which could easily be avoided by applying engineering to the problem at hand. What does this mean for us?&lt;/p&gt;

&lt;h2&gt;
  
  
  ISP
&lt;/h2&gt;

&lt;p&gt;The Interface Segregation Principle states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;no client should be forced to depend on methods it does not use&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's consider a typical scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sumNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$numbers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$limit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$numbers&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nv"&gt;$limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nv"&gt;$number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most frequently, this is the sort of thing developers would write when it's necessary to perform some kind of operation on elements of a list. The way this list is consumed here is by iterating over its elements, starting from the first one and until either the end or the limit have been reached, using a simple &lt;code&gt;foreach&lt;/code&gt; loop. Nothing else is done to this list of numbers, besides iterating over it in the given order. And yet, we are asking for an &lt;code&gt;array&lt;/code&gt;, as if we would need to access or modify its elements directly, or in random order. What if the consumer of &lt;code&gt;sumNumbers()&lt;/code&gt; has an infinite set of numbers and just wants to know the sum of the first 1000? The signature does not permit that, because nothing but an array must be passed. A type defines ways in which values of that type may be consumed, and looking at &lt;a href="https://www.php.net/manual/en/class.arrayaccess.php" rel="noopener noreferrer"&gt;&lt;code&gt;ArrayAccess&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.php.net/manual/en/class.iterator.php" rel="noopener noreferrer"&gt;&lt;code&gt;Iterator&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://www.php.net/manual/en/class.countable.php" rel="noopener noreferrer"&gt;&lt;code&gt;Countable&lt;/code&gt;&lt;/a&gt;, which together make up the true interface of an &lt;code&gt;array&lt;/code&gt;, we see that this type is in reality far more &lt;em&gt;complex&lt;/em&gt; than is let on by the &lt;em&gt;ease&lt;/em&gt; of its use. But simplicity is not about ease, and a &lt;a href="https://3v4l.org/4HsEK" rel="noopener noreferrer"&gt;much simpler version&lt;/a&gt; of the function affords us incredible flexibility compared to its former state - without even changing anything about the algorithm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sumNumbers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;iterable&lt;/span&gt; &lt;span class="nv"&gt;$numbers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$limit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nf"&gt;sumNumbers&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nv"&gt;$k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nv"&gt;$k&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})(),&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new consumer of &lt;code&gt;sumNumbers()&lt;/code&gt; can now use any series of numbers, finite or infinite, generated, hard-coded, or loaded from an external source.&lt;/p&gt;

&lt;p&gt;Another example of array usage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$fullName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nv"&gt;$fullNameSegments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'first_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'last_name'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fullNameSegments&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$segment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$segment&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$fullName&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$segment&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$fullName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only way that the &lt;code&gt;$user&lt;/code&gt; argument is consumed is by accessing its specific, discreet indices. If the consumer wanted to use something that is only capable of exposing discreet members, which would actually be enough for the algorithm to work, they cannot! Let's consider a &lt;a href="https://3v4l.org/kn7II" rel="noopener noreferrer"&gt;simplified version&lt;/a&gt;, where we depend only on what we actually use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;MapInterface&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$fullName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nv"&gt;$fullNameSegments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'first_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'last_name'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fullNameSegments&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$segment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$segment&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$fullName&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$segment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;implode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$fullName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;MapInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;MapInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;array_key_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RangeException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Key %1$s not found'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;array_key_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'first_name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Xedin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'last_name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Unknown'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'12345'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;MapInterface&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nf"&gt;getGreeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the new &lt;code&gt;getGreeting()&lt;/code&gt; only consumes as well as requires the methods of a map, any compatible map can be used, whether hard-coded, loaded from a database, de-serialized, or from a remote API. Cases such as with a remote API or some key-value storages are especially curious here, because they may not allow the listing of all entries, while supporting retrieval/checking by key, and so cannot be represented by an array because its "members" are not enumerable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Representation
&lt;/h2&gt;

&lt;p&gt;Often, data needs to be encoded in text form in order to be saved or transferred. In these cases, some kinds of &lt;a href="https://en.wikipedia.org/wiki/Data_transfer_object" rel="noopener noreferrer"&gt;DTO&lt;/a&gt;s are used in order to represent that data in the program. Let's looks at a typical example of some remote API response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"users"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xedin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"first_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Xedin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"last_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Unknown"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jsmith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"first_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"last_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Smith"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response data contains a map with a single member &lt;code&gt;users&lt;/code&gt;, which corresponds to a list, where every member is a map with members &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;username&lt;/code&gt;, &lt;code&gt;first_name&lt;/code&gt;, and &lt;code&gt;last_name&lt;/code&gt;. This is because JSON is a very simple interchange format, and supports maps and lists. Note that there is no such thing as an "ordered map": looking at such a response, we understand quite intuitively and rather well that each "user" representation has a &lt;em&gt;schema&lt;/em&gt;, which dictates certain mandatory (and perhaps some optional) fields, and in an application this data will be retrieved by key that is known in advance - because the application is written in accordance with the schema. There is never really a need to get &lt;em&gt;all&lt;/em&gt; fields of a user. Let's look at a solution for a typical problem, where entries support arbitrary fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"users"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xedin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"first_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Xedin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"last_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Unknown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"meta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"date_of_birth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1970-01-01"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hair_colour"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;  
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds support for an arbitrary number of arbitrary members through metadata in the &lt;code&gt;meta&lt;/code&gt; member of each user, which is a &lt;em&gt;list of maps&lt;/em&gt;, each map with key-value pairs, but can at any time receive additional members if necessary, such as a &lt;code&gt;type&lt;/code&gt; which could determine the data or field type of the member. This is structurally very similar to how data is stored in various engines, be it EAV (Magento 1), WordPress (meta tables), some other relational or key-value storage, etc, and allows a simple and seamless flow between the HTTP, the application, and the data layers.&lt;/p&gt;

&lt;p&gt;So then, why should the DTO type structure be any different from the schema? If we wanted to represent the entities from the above data in a PHP API, this is what it could look like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UsersResponseInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @return iterable&amp;lt;UserInterface&amp;gt;
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;iterable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getUsername&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getFirstName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getLastName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * @return iterable&amp;lt;MetaInterface&amp;gt;
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getMeta&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;iterable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;MetaInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;float&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, each user is represented by a &lt;code&gt;UserInterface&lt;/code&gt; instance, which is a data object that via its methods exposes the members of each "users" entry. Conceptually, it is consumed as a simple map, by knowing its exact getter method names (keys), and in no other way. The design of arbitrary metadata support follows a similar approach. For convenience, the metadata can also be represented as a map by simply augmenting the &lt;code&gt;UserInterface&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;MetaMapAwareInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getMetaMap&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;MapInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;UserInterface&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;MetaMapAwareInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getId&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getUsername&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getFirstName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getLastName&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * @return iterable&amp;lt;MetaInterface&amp;gt;
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getMeta&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;iterable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Inherits `getMetaMap()`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/** @var $user UserInterface */&lt;/span&gt;
&lt;span class="nv"&gt;$meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getMetaMap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$meta&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'date_of_birth'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$meta&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'date_of_birth'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: In the above example, generic syntax in e.g. &lt;code&gt;iterable&amp;lt;MapInterface&amp;gt;&lt;/code&gt; may not be supported by PHPDoc natively, but is probably supported by your IDE, and is definitely supported by &lt;a href="https://psalm.dev/" rel="noopener noreferrer"&gt;Psalm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In fact, a more generic DTO type structure could be achieved by converting all maps to an e.g. &lt;code&gt;MapInterface&lt;/code&gt;, and all lists to an &lt;code&gt;iterable&lt;/code&gt;. Since these are the only two compound types necessary, any datastructure can be represented in lists of maps of lists etc. Following the ISP principle allows great flexibility, because any such structure can be parsed by a uniform algorithm, preserve more type information, and any part of it can be replaced by one that comes from another source, or retrieves data in a different way, or generates mock data on the fly - or anything else, really, and the meaning of the program or the logic of your DTO's consumers need not change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Indexing
&lt;/h3&gt;

&lt;p&gt;Another very common thing PHP developers do, and which can be found in the code of most frameworks, is something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
 * @return array&amp;lt;UserInterface&amp;gt; A list of users, by ID.
 */&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;get_users&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Retrieves users from DB...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the value returned by &lt;code&gt;get_users()&lt;/code&gt; betrays the principles described in this article. While it is perfectly reasonable and valuable to have an index, index does not imply any &lt;em&gt;order&lt;/em&gt;, but simply the ability to reference a whole record &lt;em&gt;directly&lt;/em&gt;, often by a combination of only some of its members. If consuming code needs an ordered set of users (for example, sorted by &lt;code&gt;first_name&lt;/code&gt;), then it is consuming the interface of a &lt;em&gt;list&lt;/em&gt; of users, and every user has the same significance to the consuming logic. If consuming code needs an index of users, where each user can be retrieved by their &lt;code&gt;id&lt;/code&gt;, then it is consuming the interface of a &lt;em&gt;map&lt;/em&gt; of users, every user has a potentially different significance, and the order is irrelevant. Naturally, it is possible to convert a list of users to an index of users at any time by simply iterating over it programmatically. Because with this separation the index is now a separate "collection" than the list, the index can even be cached separately - like databases do, but also in memory, in a file like JSON, etc. With some additional logic, such an index can easily be used as an entity repository, which is usually unable to reliably enumerate its members.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Here are some practical take-aways that I would like to suggest.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Achieve parity across your application layers by representing all data in a documented format with a single source of truth.&lt;/li&gt;
&lt;li&gt;It's either a map or a list. It's not both. If you think you need both, it's a good sign that your design could be simplified.&lt;/li&gt;
&lt;li&gt;Do not restrict the consumers of your APIs to using native types. Strings, lists, and maps can all be generated on the fly, in different ways, and there's no reason to limit how your consumers acquire the data they pass to your code.&lt;/li&gt;
&lt;li&gt;Observe ISP on one hand, and on the other - always depend on the most narrow type that provides the necessary interface. The &lt;code&gt;array&lt;/code&gt; type is far too wide for most cases.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>php</category>
    </item>
    <item>
      <title>Separation of Concerns and SOLID</title>
      <dc:creator>Anton Ukhanev</dc:creator>
      <pubDate>Thu, 23 Jul 2020 10:57:32 +0000</pubDate>
      <link>https://forem.com/xedinunknown/separation-of-concerns-3e7d</link>
      <guid>https://forem.com/xedinunknown/separation-of-concerns-3e7d</guid>
      <description>&lt;p&gt;I would like to start with a quote of E.W. Dijkstra, from his 1974 paper "On the role of scientific thought":&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let me try to explain to you, what to my taste is characteristic for all intelligent thinking. It is, that one is willing to study in depth an aspect of one's subject matter in isolation for the sake of its own consistency, all the time knowing that one is occupying oneself only with one of the aspects. We know that a program must be correct and we can study it from that viewpoint only; we also know that it should be efficient and we can study its efficiency on another day, so to speak. In another mood we may ask ourselves whether, and if so: why, the program is desirable. But nothing is gained —on the contrary!— by tackling these various aspects simultaneously. It is what I sometimes have called "the separation of concerns", which, even if not perfectly possible, is yet the only available technique for effective ordering of one's thoughts, that I know of. This is what I mean by "focusing one's attention upon some aspect": it does not mean ignoring the other aspects, it is just doing justice to the fact that from this aspect's point of view, the other is irrelevant. It is being one- and multiple-track minded simultaneously&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we want to make our code resilient to the negative effects of change i.e. make it more adaptable to change without breaking, as well as to make it simple to understand and modify, we need to separate concerns very well. But what does it mean - to have a concern? And how do we determine what the concern of a module is?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: if you understand why and how concerns are separated, but not sure what to do in practice, learn how to &lt;a href="https://dev.to/xedinunknown/cross-platform-modularity-in-php-30bo"&gt;make cross-platform modules in PHP&lt;/a&gt;. You are also encouraged to read Alain Schlesser's excellent article &lt;a href="https://www.alainschlesser.com/config-files-for-reusable-code/"&gt;Using A Config To Write Reusable Code&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is an example. Let's say, our project is a car, and we need an engine to run it. The engine needs something to ignite the fuel in a cylinder - a spark plug. Would you make a spark plug built in, baked into the engine? Of course not! When it comes to physical things, nobody in their right mind would do something like that. We would just "know" that spark plugs need to be separate. How do we know that?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We know that because the lifetime of an engine is much greater than the lifetime of a spark plug. We know that spark plugs have a tendency to get burned, or malfunction in other ways - due to their softer materials and complex construction (as opposed to a cylinder), and therefore they will have to be changed frequently; whereas an cylinder has a very long lifetime because it is made of metal, and therefore it will need to be changed less frequently.&lt;/li&gt;
&lt;li&gt;We also know that because the problems that can cause an engine or cylinder to be changed are a different kind of problems rather than what could cause a spark plug to be changed: cylinder heads can get scratched or otherwise damaged from the friction with the cylinder, and this happens at a relatively slow rate (they're made of metal, and are lubricated with oil), whereas spark plugs are prone to all kinds of damage related to the wear of isolation components, due to electric currents passing through the conducting materials, or perhaps dampness, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, we can determine two basic rules that determine a concern of a component:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The frequency, with which the components need to be changed.&lt;/li&gt;
&lt;li&gt;The reasons, for which the components need to be changed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Effectively, an engine with separate spark plugs does not decide which spark plugs to use; instead, it is decided by the engineer who is assembling the car out of its components.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If some code needs to change at a different rate than other code, or for different reasons than other code, then we know that those two units of code have different concern.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a direct result of the above, this gives us the corresponding benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;One unit can be changed more frequently than another, without causing the need for that other code to change.&lt;/li&gt;
&lt;li&gt;One unit can be changed for different reasons than another, without causing the need for that other code to change.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Like this, we have made our code more adaptable to change. This gives us great flexibility, because we can choose any component of the system, and make it do stuff completely differently, according to our changing needs, without breaking or changing any other part of the software. With each iteration we write more and more code which does stuff; but this means that with each iteration we have more and more code that we need to keep in mind when doing these changes. And our mental capacity is limited, our minds can only hold so many things at once. When code is adaptable to change, the amount of things that we need to hold in our minds reduces by an order of magnitude, because things that are logically unrelated become actually unrelated, allowing us to focus on only one concern, without thinking of how it affects our ways of addressing other concern. This gives us tremendous agility, and development speeds do not fall but grow, because with every component we write there is one less component to write when we want to address the same concern again. This kind of agility - the ability to affect the greatest amount of change with the least amount of effort - is the ultimate type of agility that is more beneficial than any other kind of agility. This is very well explained by &lt;a href="https://twitter.com/richhickey"&gt;Rich Hickey&lt;/a&gt; in his talk "&lt;a href="https://www.youtube.com/watch?v=rI8tNMsozo0"&gt;Simplicity Matters&lt;/a&gt;", which I take great inspiration from.&lt;/p&gt;

&lt;p&gt;And so, for example, using a PSR-18 HTTP Client is good, better than directly using WP's HTTP client, because it allows us to de-couple ourselves from WP, and because it is re-usable, etc, making things easy. But we do not use a PSR-18 HTTP client because it's easy; we use it because it is the correct way to do it: a module, whose purpose is to access a REST API, does not decide which HTTP client to use; instead it is decided by the engineer who is assembling the application out of these components. And for the purposes of a WordPress plugin, they decide to use an HTTP client that makes requests through WordPress, because this is the appropriate transport that would ensure compatibility with WordPress and its extensions. All the benefits that this abstraction brings are therefore simply useful and desirable side effects of following the Separation of Concerns principle, which corresponds to &lt;a href="https://dev.toSRP"&gt;Single Responsibility Principle&lt;/a&gt; - the S in SOLID.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An engineer should not be at the mercy of the components that they use; an engineer should be in control of components, assembling their system as it is necessary for the purpose of their task. It is an engineer's decision which components to use; it is not the decision of some other code that they are forced to use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  SOLID Principles
&lt;/h2&gt;

&lt;p&gt;In practice, Separation of Concerns would mean making units of code smaller. If a class has too much responsibility, which we can understand by applying the rationale described above, we split it into multiple classes, and the same is applied to functions. We do that by establishing the concerns addressed by our unit, and creating multiple smaller units, each of which has a narrow and well-defined concern of its own. However, the original logic made all these concerns play together, and thus we need a way for one unit to invoke another, naturally causing our units to &lt;em&gt;depend&lt;/em&gt; on other units. Our classes start depending on other classes, and these dependencies are most often fulfilled by using &lt;a href="https://en.wikipedia.org/wiki/Dependency_injection"&gt;Dependency Injection&lt;/a&gt;: a class receives dependencies, including instances of other classes, via its constructor parameters. This is the process of &lt;em&gt;configuration&lt;/em&gt;, as opposed to consumption, because it sets some values that are internal to the class, and that consumers of the class don't necessarily see.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open-Closed Principle
&lt;/h3&gt;

&lt;p&gt;With our units now addressing separate concerns, they move closer to being compliant with the &lt;a href="https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle"&gt;Open-Closed Principle&lt;/a&gt; (OCP). If our unit is a class, for example, outside code cannot modify its logic, but it can change the logic of its dependencies, decreasing the need for modification, and thus making our system more adaptable to change.&lt;/p&gt;

&lt;p&gt;There is an opinion that it is best to make classes &lt;code&gt;final&lt;/code&gt;, i.e. non-extendable. This encourages &lt;a href="https://en.wikipedia.org/wiki/Composition_over_inheritance"&gt;Composition Over Inheritance&lt;/a&gt;, which is a good thing, but also brings about a slew of problems, such as the necessity to write forwarding method implementations. The most important drawback here is that a &lt;a href="https://en.wikipedia.org/wiki/Decorator_pattern"&gt;decorating&lt;/a&gt; class has no way of overwriting a method of the base class, even if the added or changed behaviour is simple. Ideally, all extension or modification of behaviour would be achieved by decoration; however, not giving developers the opportunity to change specific methods of the base class through inheritance assumes that the base is written &lt;em&gt;perfectly&lt;/em&gt;, e.g. that it addresses only a single concern, injects all dependencies, etc. I conclude that composition should always be preferred over inheritance; but because it is not always possible or feasible, class authors should not put a hard boundary for inheritance, allowing it to be usable when necessary. For example, wen using a third-party library, it may be necessary to make changes to the behaviour of some service, and if (this happens often) the service has too much responsibility, developers are forced to either copy-paste code, or abandon the attempt to adapt the service altogether. Ultimately, these are two different concerns: service authors should not limit consumers of the service; at the same time, consumers should use services in a way that leads to better architecture.&lt;/p&gt;

&lt;p&gt;Thus, separation of concerns leads to the Open-Closed principle, &lt;em&gt;reducing (or localizing) the need for changes&lt;/em&gt;, and keeping code units open for extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  Liskov Substitution Principle
&lt;/h3&gt;

&lt;p&gt;A common way of adding responsibility is by sub-typing, which usually means either extension of a class, or by using composition in conjunction with extension of an interface. Either way, both methods lead to the creation of a sub-type - a descendant of a super-type, and this new type may add responsibilities by declaring additional methods. So if type &lt;code&gt;A&lt;/code&gt; has method &lt;code&gt;one()&lt;/code&gt;, its sub-type &lt;code&gt;B&lt;/code&gt; may add responsibilities by declaring method &lt;code&gt;two()&lt;/code&gt;, resulting this subtype having both methods. As a real-life example, a smartphone has all the characteristics of a phone in the sense that it allows one to make phone calls, but it also has additional features, such as the address book.&lt;/p&gt;

&lt;p&gt;Following the smartphone example above, we can see that a smartphone &lt;em&gt;is&lt;/em&gt; also a phone. This dictates that it &lt;em&gt;must be usable as a phone, without the knowledge of any additional features&lt;/em&gt; if these features are not required. The &lt;a href="https://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov Substitution Principle&lt;/a&gt; (LSP) codifies this, and is represented in the PHP engine itself in the form of certain inheritance rules, such as &lt;a href="https://www.php.net/manual/en/language.oop5.variance.php"&gt;variance&lt;/a&gt;. Developers do not need to remember many of the aspects of the LSP, as they are forced to comply by PHP, which is moving closer to complete implementation of the principle every year through improvements in its syntax and the rules applied during compilation.&lt;/p&gt;

&lt;p&gt;Thus, we can see that the Liskov Substitution Principle is derived from the Separation of Concerns principle, as it allows us to invoke the concerns of a sub-type inherited from its super-type without knowing of the specifics of the sub-type, &lt;em&gt;allowing those specifics to change&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interface Segregation Principle
&lt;/h3&gt;

&lt;p&gt;When depending on an injected type, the consuming class promises that it will not use any API other than of that type. While providing a large degree of predictability, this is still not perfectly safe: the injected type may change in the future, possibly breaking some of the previously declared API. For this reason, consumers should use only the API they really need - see "Dependency Inversion Principle".&lt;/p&gt;

&lt;p&gt;On the other hand, consumers can only depend on a type that is declared, and therefore, if a more narrow type is not available, they are forced to declare dependency on an API that they do not consume. The &lt;a href="https://en.wikipedia.org/wiki/Interface_segregation_principle"&gt;Interface Segregation Principle&lt;/a&gt; (ISP) codifies the rule that allows consumers to depend only on what they need, giving everything else the &lt;em&gt;freedom to change&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Inversion Principle
&lt;/h3&gt;

&lt;p&gt;Injection of services requires the declaration of dependencies, and the other SOLID principles tell us among other things how we should do that. But what of the type itself? If a class that contains the necessary functionality exists, is it fine to simply depend on it?&lt;/p&gt;

&lt;p&gt;Not always. It makes no sense to declare dependency on an API that is not consumed, thus increasing useless coupling, and introducing discrepancy between actual and declared dependency. According to ISP, a type should declare an API that relates to only the specific concerns of that type. DIP is the opposite side of that: consumers should depend on only the API they need, in its &lt;em&gt;most generic form&lt;/em&gt;. If type &lt;code&gt;A&lt;/code&gt; declares method &lt;code&gt;one()&lt;/code&gt;, and its sub-type &lt;code&gt;B&lt;/code&gt; declares method &lt;code&gt;two()&lt;/code&gt;, given that we are only going to use method &lt;code&gt;one()&lt;/code&gt;, we must depend on type &lt;code&gt;A&lt;/code&gt;, and not type &lt;code&gt;B&lt;/code&gt;. Thus, DIP allows implementations to &lt;em&gt;change freely&lt;/em&gt; as long as they do not break their dependents by making sure that declared dependencies correspond to actual ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Following SOLID principles results in software that is &lt;strong&gt;adaptable to change&lt;/strong&gt; and &lt;strong&gt;resilient to negative effects of change&lt;/strong&gt;, because it, among other things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makes sure that a unit of code changes only in response to changes of &lt;em&gt;its&lt;/em&gt; concern.&lt;/li&gt;
&lt;li&gt;Makes units of code de-coupled from logic that &lt;em&gt;is not their concern&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Makes relationships between units of code very &lt;em&gt;predictable, yet flexible&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Makes APIs more &lt;em&gt;stable and reliable&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Lowers the complexity&lt;/em&gt; of individual components, making them easier to understand, use, and change.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Increases re-usability&lt;/em&gt; of individual components, making it possible to re-combine them for a different result.&lt;/li&gt;
&lt;li&gt;Allows for better application of &lt;a href="https://en.wikipedia.org/wiki/Package_principles"&gt;Package Management Principles&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Decreases maintenance costs&lt;/em&gt; as a result of the above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, the most important benefit, which could be made into a principle of its own is the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The responsibility of a software engineer is to understand the problem domain, and translate its processes and entities into a language that a computer can understand, thus creating a model of the problem domain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The more accurate this model is, the more predictable, reliable, and flexible the behaviour of the software becomes. By following SOLID principles, software engineers can ensure that their models of problem domains are very accurate. These principles are natural, because they reflect the nature of logical concepts, and following them is a natural conseqence of normalization and optimization. This has many positive side effects, such as high maintainability, or a high level of re-use. These side effects appear automatically, as a consequence of the high level of model accuracy, and while desirable, they are not the main goal of SOLID principles; yet they will be naturally acquired simply by following these principles. Abstraction therefore is something that should be done immediately, as soon as the need for it arises; yet it is not &lt;em&gt;for the sake of being there&lt;/em&gt;, but in order to correctly represent the problem domain by applying SoC.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[...] whatsoever is contrary to nature is also contrary to reason, and whatsoever is contrary to reason is absurd, and, ipso facto, to be rejected.&lt;br&gt;
— &lt;strong&gt;Benedict de Spinoza&lt;/strong&gt;, "A Theologico-Political Treatise&lt;cite&gt;", 1883&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>separationofconcerns</category>
      <category>soc</category>
      <category>architecture</category>
      <category>solid</category>
    </item>
    <item>
      <title>Cross-Platform Modularity in PHP</title>
      <dc:creator>Anton Ukhanev</dc:creator>
      <pubDate>Tue, 02 Jun 2020 13:59:27 +0000</pubDate>
      <link>https://forem.com/xedinunknown/cross-platform-modularity-in-php-30bo</link>
      <guid>https://forem.com/xedinunknown/cross-platform-modularity-in-php-30bo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Notice&lt;/em&gt;: There's an on-going discussion in support of the underlying Service Provider standard. &lt;a href="https://github.com/container-interop/service-provider/issues/51" rel="noopener noreferrer"&gt;Join the effort&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;For over 12 years now, I have been working with various engines and frameworks, from &lt;a href="https://codeigniter.com/" rel="noopener noreferrer"&gt;CodeIgniter&lt;/a&gt; to &lt;a href="https://magento.com/" rel="noopener noreferrer"&gt;Magento&lt;/a&gt;, but the greatest amount of time I have spent on projects related to &lt;a href="https://wordpress.org/" rel="noopener noreferrer"&gt;WordPress&lt;/a&gt;. One of my biggest passions is re-usability, and so by far, I have spent most of my WordPress time on plugins, working with companies and teams to produce high-quality, customizable solutions.&lt;/p&gt;

&lt;p&gt;Of course, there's no quality and re-usability without interoperability, and without design principles like &lt;a href="https://en.wikipedia.org/wiki/SOLID" rel="noopener noreferrer"&gt;SOLID&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Domain-driven_design" rel="noopener noreferrer"&gt;DDD&lt;/a&gt;. That's why they are my other great passion. I have been in trouble countless times for pushing for better standards and refusing to write low-quality code.&lt;/p&gt;

&lt;p&gt;In PHP, when we think "&lt;a href="https://en.wikipedia.org/wiki/Interoperability" rel="noopener noreferrer"&gt;interoperability&lt;/a&gt;", we think "&lt;a href="http://php-fig.org/" rel="noopener noreferrer"&gt;FIG&lt;/a&gt;". And I have been a fan of FIG for a long time, even making it into a workgroup. Although I don't always like or agree with everything FIG does, it is an organization that takes interop standards very seriously. And we need interop standards.&lt;/p&gt;

&lt;p&gt;In fact, we need them yesterday, and there simply aren't enough resources at FIG to provide for everyone. At the same time, FIG is quite a rigid organization (for good reason), which is why I created &lt;a href="https://github.com/Dhii/" rel="noopener noreferrer"&gt;Dhii&lt;/a&gt;: to serve as a more flexible source of standards and compliant implementations, providing a testing ground for ideas and contributing to interoperability in more niche areas. For example, it is not uncommon to use a &lt;code&gt;__toString()&lt;/code&gt; method for converting objects to their string representation, but for some reason, PHP is missing a native interface that would allow us to type-hint (or at least document) that a &lt;a href="https://github.com/Dhii/stringable-interface/blob/develop/src/StringableInterface.php" rel="noopener noreferrer"&gt;stringable object&lt;/a&gt; is an allowed type. The same goes for many other things, like &lt;a href="https://github.com/Dhii/data-identifiable-interface/blob/develop/src/IdAwareInterface.php" rel="noopener noreferrer"&gt;ID-aware objects&lt;/a&gt;, objects with human-readable data like &lt;a href="https://github.com/Dhii/human-readable-interface/blob/develop/src/LabelAwareInterface.php" rel="noopener noreferrer"&gt;labels&lt;/a&gt; and &lt;a href="https://github.com/Dhii/human-readable-interface/blob/develop/src/CaptionAwareInterface.php" rel="noopener noreferrer"&gt;captions&lt;/a&gt;, &lt;a href="https://github.com/Dhii/output-renderer-interface/blob/develop/src/TemplateAwareInterface.php" rel="noopener noreferrer"&gt;templates&lt;/a&gt; and other output-related objects, and many more. At Dhii, we address these concerns in hope that our solutions would help packages to be more interoperable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modularity
&lt;/h2&gt;

&lt;p&gt;One of these concerns is &lt;a href="https://en.wikipedia.org/wiki/Modularity" rel="noopener noreferrer"&gt;modularity&lt;/a&gt;. Many systems lack the notion of modules. WordPress allows for plugins, themes, drop-ins, etc., but nothing unifies them. I describe the problem and solutions in detail in my article "&lt;a href="https://inpsyde.com/en/package-management-in-wordpress-introduction-solutions/" rel="noopener noreferrer"&gt;Package Management in WordPress&lt;/a&gt;". Other systems, like &lt;a href="https://symfony.com/doc/current/bundles.html" rel="noopener noreferrer"&gt;Symfony&lt;/a&gt;, support modules, but they are coupled to those systems, and therefore cannot be used anywhere else. Moreover, if your WordPress plugin needs to be modular itself — perhaps because you want to support add-ons that would extend its core functionality — there is no available standard in WordPress or anywhere else to make that possible.&lt;/p&gt;

&lt;p&gt;With all the interop standards that already exist and have yet to come, why not have modules that can work in any system, provided that it has a compatible loader? Wouldn't it be great if a piece of functionality that addresses a business problem in WordPress could also be used in Drupal? Why do we have to write the same thing so many times, over and over again? I cannot even imagine how much time and money gets spent on re-inventing the wheel every day.&lt;/p&gt;

&lt;p&gt;Meet &lt;a href="https://github.com/Dhii/module-interface" rel="noopener noreferrer"&gt;&lt;code&gt;dhii/module-interface&lt;/code&gt;&lt;/a&gt;: a standard for cross-platform modules. Dependent on a FIG experimental &lt;a href="https://github.com/container-interop/service-provider" rel="noopener noreferrer"&gt;service-provider&lt;/a&gt; standard, it allows you to quickly and easily define a cross-platform module for use in any system with a compatible loader. How you program the module internals, including the level of granularity for declared services, is entirely up to you; but when done correctly, it automatically allows every individual part of your module to be infinitely extendable from outside. One module can completely change the way another module works. And yet, the application comprised of these modules is ultimately in control. Here's how this is achieved.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If you don't understand why you would want cross-platform modules with easily changeable components, you may want to learn about &lt;a href="https://dev.to/xedinunknown/separation-of-concerns-3e7d"&gt;Separation of Concerns&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Inversion of Control
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Traditional Approach
&lt;/h4&gt;

&lt;p&gt;In most cases, a modular application includes some entry points which can be used by modules to interrupt or extend the flow of the application. In such systems, &lt;em&gt;modules are made &lt;strong&gt;for&lt;/strong&gt; the application&lt;/em&gt;, and can change only the aspects open for change by the application or other modules. Often, this is done via an event mechanism: the application would trigger an event which can be handled by module handlers; those would change some parameters of the event; these parameters would then be returned and used by the original code. For example, WordPress uses &lt;a href="https://developer.wordpress.org/plugins/hooks/" rel="noopener noreferrer"&gt;hooks&lt;/a&gt; to de-couple plugin code from its internal flow. These are some of the problems such a mechanism suffers from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The event system is often proprietary, making any consumers (plugins) coupled to it.&lt;/li&gt;
&lt;li&gt;The consumers can only modify the data that is exposed via the events, leaving all other aspects set in stone, which greatly limits what modules can do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if a system does not use events, but relies on some other mechanism, such as service definitions, the module standard would be specific to that system, and you would not be able to re-use the same module somewhere else.&lt;/p&gt;

&lt;h4&gt;
  
  
  A Better Approach
&lt;/h4&gt;

&lt;p&gt;Ideally, the application would have no more than the following responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Combining individual parts. That is, implementing a mechanism for loading interoperable modules. This includes setting the load order.&lt;/li&gt;
&lt;li&gt;Linking with a bigger system, if necessary. For example, a modular WordPress plugin is a part of WordPress, and so it would provide a bridge between the services of application modules, and WordPress.&lt;/li&gt;
&lt;li&gt;Satisfying module dependencies. For example, modules may depend on an HTTP client, and the application can satisfy that dependency, thus deciding the HTTP client implementation used by the modules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With such responsibility distribution, the application chooses which modules to load, how and when. For example, If an application needs logging capabilities, it may choose to use a module that addresses that concern. But that logging module may require a filesystem abstraction, and the application would be responsible for satisfying that requirement. The application may choose to load another module or library which provides that abstraction. Thus, &lt;em&gt;the application is &lt;strong&gt;for&lt;/strong&gt; modules&lt;/em&gt;, inverting control, taking it from modules into its own hands.&lt;/p&gt;

&lt;h4&gt;
  
  
  Module Loading
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhgjvskucdg7bp488hmtw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhgjvskucdg7bp488hmtw.png" alt="Module Loading"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the main responsibilities of the application is loading the selected modules, and a crucial part of that is determining the module load order. This order has a direct effect on the services that will effectively be used in the application. The module standard relies on service-provider implementations exposed by the modules. These Service Providers expose service definitions in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Factories. The definitions returned by &lt;a href="https://github.com/container-interop/service-provider/blob/master/src/ServiceProviderInterface.php#L21" rel="noopener noreferrer"&gt;&lt;code&gt;getFactories()&lt;/code&gt;&lt;/a&gt; completely &lt;strong&gt;override&lt;/strong&gt; definitions of the same service factories that were declared in the modules loaded before. In other words, &lt;strong&gt;the last definition wins&lt;/strong&gt;. All &lt;strong&gt;other service factories are not used in the application&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Extensions. The definitions returned by &lt;a href="https://github.com/container-interop/service-provider/blob/master/src/ServiceProviderInterface.php#L40" rel="noopener noreferrer"&gt;&lt;code&gt;getExtensions()&lt;/code&gt;&lt;/a&gt; are &lt;strong&gt;applied on top&lt;/strong&gt; of the same service extensions that were declared in the modules loaded before. In other words, &lt;strong&gt;later definitions extend earlier ones&lt;/strong&gt;. All &lt;strong&gt;extensions are always applied&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And here is how the modules are loaded by a compliant system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;All module instances are retrieved.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;setup()&lt;/code&gt; method of all modules is invoked, and the exposed service providers are used to configure a single DI container.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;run()&lt;/code&gt; method of all modules is invoked, providing all configuration to each module via the DI container.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This creates an extremely simple yet powerful mechanism for modules to influence other modules in a way that is completely predictable, with one DI container being the &lt;a href="https://en.wikipedia.org/wiki/Single_source_of_truth" rel="noopener noreferrer"&gt;single source of truth&lt;/a&gt; for &lt;em&gt;all configuration&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A module's service provider exposed by &lt;a href="https://github.com/Dhii/module-interface/blob/develop/src/ModuleInterface.php#L34" rel="noopener noreferrer"&gt;&lt;code&gt;setup()&lt;/code&gt;&lt;/a&gt; declares all services used by it.&lt;/li&gt;
&lt;li&gt;These services are consumed by the &lt;a href="https://github.com/Dhii/module-interface/blob/develop/src/ModuleInterface.php#L51" rel="noopener noreferrer"&gt;&lt;code&gt;run()&lt;/code&gt;&lt;/a&gt; method via a standard &lt;a href="https://github.com/php-fig/container/blob/master/src/ContainerInterface.php" rel="noopener noreferrer"&gt;container&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Any module can access any service declared by any other module, because they are all available via the single source of truth.&lt;/li&gt;
&lt;li&gt;Any module can extend or completely override any service declared by any other module, and the application decides the priority via the module load order.&lt;/li&gt;
&lt;li&gt;A module may explicitly delegate a service to another module by not declaring it, and the application will then satisfy that dependency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an illustration of how service definitions would resolve according to the rules described above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3et97km0wrapgscno2bb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3et97km0wrapgscno2bb.png" alt="Service Resolution"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following can be gathered from this illustration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The modules are loaded in order: first &lt;code&gt;Module1&lt;/code&gt;, then &lt;code&gt;Module2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When requesting services &lt;code&gt;B&lt;/code&gt;, &lt;code&gt;D&lt;/code&gt;, and &lt;code&gt;E&lt;/code&gt;, they would be retrieved from definitions of modules 1, 2, and 2, respectively. This is because they are declared there, and not overridden or extended anywhere later.&lt;/li&gt;
&lt;li&gt;The service &lt;code&gt;C&lt;/code&gt; is first &lt;em&gt;declared&lt;/em&gt; in &lt;code&gt;Module&lt;/code&gt;, but then &lt;em&gt;overridden&lt;/em&gt; by that in &lt;code&gt;Module2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The service &lt;code&gt;A&lt;/code&gt; is &lt;em&gt;declared&lt;/em&gt; in &lt;code&gt;Module1&lt;/code&gt;, and then &lt;em&gt;extended&lt;/em&gt; in &lt;code&gt;Module2&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Out of the box, there is complete customizability and flexibility, without sacrificing centralization and control. Modules are self-contained, and depend on outside services through the DI container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started
&lt;/h3&gt;

&lt;p&gt;So, how would one start working in a modular system like this, and what would it take to make a simple application?&lt;/p&gt;

&lt;h4&gt;
  
  
  Bootstrap
&lt;/h4&gt;

&lt;p&gt;To fulfill its main responsibility, the application must load modules in an order pre-determined by it; the application must bootstrap the module system. If the module classes do not require any parameters in their constructors, the bootstrap could be as simple as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Dhii\Modular\Module\ModuleInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Interop\Container\ServiceProviderInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Some\Container&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;MyPackage\Module&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;ModuleA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;OtherPackage\Module&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;ModuleB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Module classes&lt;/span&gt;
&lt;span class="nv"&gt;$modulesToLoad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;ModuleA&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;ModuleB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// A container implementation that supports service providers&lt;/span&gt;
&lt;span class="nv"&gt;$container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="cm"&gt;/* @var ModuleInterface[] */&lt;/span&gt;
&lt;span class="nv"&gt;$modules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="c1"&gt;// Get the modules' services&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$modulesToLoad&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$moduleClassName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Instantiate the module&lt;/span&gt;
    &lt;span class="nv"&gt;$module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nv"&gt;$moduleClassName&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Keep track of module instances&lt;/span&gt;
    &lt;span class="nv"&gt;$modules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$moduleClassName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$module&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Retrieve the services&lt;/span&gt;
    &lt;span class="nv"&gt;$provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$module&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Add the services to the container&lt;/span&gt;
    &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$provider&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Run the modules&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$modules&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$module&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all; barring comments, imports, and whitespace, all it takes to have a simple modular system is 20 lines of code. Module classes in this example get autoloaded like any other class.&lt;/p&gt;

&lt;h4&gt;
  
  
  A module
&lt;/h4&gt;

&lt;p&gt;A module may provide services, consume services, or both. Let's create a simple module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyPackage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Dhii\Modular\Module\ModuleInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Container\ContainerInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Module&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;ModuleInterface&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;ServiceProviderInterface&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ServiceProvider&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'my_service'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ContainerInterface&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;MyService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// A dependency&lt;/span&gt;
                &lt;span class="nv"&gt;$otherService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$c&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'other_service'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="c1"&gt;// Perhaps a class declared in this package&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$otherService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ContainerInterface&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Retrieve a service - may have been overridden or extended elsewhere&lt;/span&gt;
        &lt;span class="nv"&gt;$myService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$container&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'my_service'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$myService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we have a module that declares a service &lt;code&gt;my_service&lt;/code&gt; of type &lt;code&gt;MyPackage\MyService&lt;/code&gt; and consumes it. That service depends on a service &lt;code&gt;other_service&lt;/code&gt;, and because it is not declared in this module, it is a dependency. The &lt;a href="https://github.com/Dhii/containers/blob/develop/src/ServiceProvider.php" rel="noopener noreferrer"&gt;&lt;code&gt;ServiceProvider&lt;/code&gt;&lt;/a&gt; class was omitted here for brevity, because implementations are extremely simple, and can even be easily created in the same package, including &lt;a href="https://www.php.net/manual/en/language.oop5.anonymous.php" rel="noopener noreferrer"&gt;anonymously&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Possibilities
&lt;/h2&gt;

&lt;p&gt;The possibilities opened up by such an architecture are limitless, including:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Submodules. A module may contain a loading mechanism itself, which would load other modules that would therefore become its submodules. This fact allows for a module hierarchy of arbitrary depth, while each module remains agnostic of its environment.&lt;/li&gt;
&lt;li&gt;Usage in non-modular applications. A modular WordPress plugin made in this way could be hooked up to the WordPress system through the DIC container, and thus may consume engine-specific things like settings, without breaking interop.&lt;/li&gt;
&lt;li&gt;Dependency graphs. Service dependencies can be analyzed statically, producing a list of services that must be added to a system for the module to work. Combined with similar lists from other modules, it is possible to search for or suggest other modules that satisfy dependencies of any particular module.&lt;/li&gt;
&lt;li&gt;Medium-agnostic configuration access. Dependency containers that draw configuration from different sources, like files, the database, or even network, can be combined into the single source of truth consumed by modules, allowing them to consume configuration values that are resolved based on the availability of the key in the above-mentioned sources. For example, service configuration is overridden by YAML configuration, which is overridden by settings stored in a database.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>php</category>
      <category>modularity</category>
    </item>
  </channel>
</rss>
