<?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/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <title>Blog entries tagged doctrine :: mwop.net</title>
    <description>Blog entries tagged doctrine :: mwop.net</description>
    <pubDate>Mon, 10 Mar 2025 08:24:34 -0500</pubDate>
    <generator>Laminas_Feed_Writer 2 (https://getlaminas.org)</generator>
    <link>https://mwop.net/blog/tag/doctrine</link>
    <atom:link rel="self" type="application/rss+xml" href="https://mwop.net/blog/tag/doctrine/rss.xml"/>
    <item>
      <title>SQL Nested Queries or Sub Queries with Doctrine DBAL</title>
      <pubDate>Mon, 10 Mar 2025 08:24:34 -0500</pubDate>
      <link>https://mwop.net/blog/2025-03-06-dbal-sub-query.html</link>
      <guid>https://mwop.net/blog/2025-03-06-dbal-sub-query.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I recently ran into a problem with my website for which the solution was a nested query (sometimes termed a subquery).
However, I use <a href="https://www.doctrine-project.org/projects/doctrine-dbal/en/4.2/index.html">Doctrine DBAL</a> for creating my dynamic queries, and there's no documentation on how to do them.</p>


<h3>The problem</h3>
<p>For my art gallery, the raw SQL looks something like the following:</p>
<pre><code class="language-sql hljs sql" data-lang="sql"><span class="hljs-keyword">SELECT</span>
    p.filename,
    p.description,
    p.created,
    array_agg(<span class="hljs-keyword">DISTINCT</span> t.tag) <span class="hljs-keyword">as</span> tags
<span class="hljs-keyword">FROM</span>
    photos p
<span class="hljs-keyword">LEFT</span> <span class="hljs-keyword">JOIN</span> tags t <span class="hljs-keyword">ON</span> p.filename = t.content_id
<span class="hljs-keyword">WHERE</span>
    p.filename = :filename
    <span class="hljs-keyword">AND</span> t.content_type = :content_type
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span>
    p.filename
</code></pre>
<p>I started noticing an odd issue where, post insertion of an image into my gallery, I'd get no error, but the form would not appear to have processed.
On further inspection, using <a href="https://www.zend.com/products/zendphp-enterprise/zendhq#tab-panel-16522">Z-Ray from ZendHQ</a>, I realized that the insertion was successful, but that the redirect to view the inserted image was returning a 404.
I grabbed the executed SQL from Z-Ray for retrieving the image, and it returned no rows.</p>
<p>I started thinking about why this image wasn't posting, when others were, and realized there was one trivial difference: I wasn't including any hashtags in my description, which meant no tags.</p>
<p>Hopefully you can see where this is leading.</p>
<p>A <code>LEFT JOIN</code> normally will not cause the entire query to fail if it finds no matching rows on the joined table; that's the behavior of <code>INNER JOIN</code>.
However, if you put a condition that is based on a joined table outside the join itself, it essentially acts like an <code>INNER JOIN</code>, as this is now a condition of the <code>SELECT</code> query.</p>
<p>Sure enough, when I removed the <code>LEFT JOIN</code> and the <code>array_agg</code> column, I got a hit.</p>
<h3>&quot;Obvious&quot; solution: move the condition</h3>
<p>As a commenter on this post noted, the immediate solution is to move the <code>AND t.content_type = :content_type</code> clause to the <code>JOIN</code>:</p>
<pre><code class="language-sql hljs sql" data-lang="sql"><span class="hljs-keyword">SELECT</span>
    p.filename,
    p.description,
    p.created,
    array_agg(<span class="hljs-keyword">DISTINCT</span> t.tag) <span class="hljs-keyword">as</span> tags
<span class="hljs-keyword">FROM</span>
    photos p
<span class="hljs-keyword">LEFT</span> <span class="hljs-keyword">JOIN</span> tags t <span class="hljs-keyword">ON</span> p.filename = t.content_id <span class="hljs-keyword">AND</span> t.content_type = :content_type
<span class="hljs-keyword">WHERE</span>
    p.filename = :filename
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span>
    p.filename
</code></pre>
<p>This does work, and requires no huge changes to the DBAL query builder; I just move the condition into the <code>joinLeft()</code>, and carry on.</p>
<h3>Preferred solution: nested query</h3>
<p>The solution I chose was to do a nested query, and to aggregate those results as an array.
This makes it more clear when reading the query as to the intent: I want to select all distinct tags for this image and assign them as an array to a column.
I'm using PostgreSQL, so the query looks like this:</p>
<pre><code class="language-sql hljs sql" data-lang="sql"><span class="hljs-keyword">SELECT</span>
    p.filename,
    p.description,
    p.created,
    (<span class="hljs-keyword">SELECT</span> <span class="hljs-built_in">ARRAY</span>(
        <span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">DISTINCT</span> tag <span class="hljs-keyword">FROM</span> tags <span class="hljs-keyword">WHERE</span> p.filename = content_id <span class="hljs-keyword">AND</span> content_type = :content_type
        )) <span class="hljs-keyword">as</span> tags
<span class="hljs-keyword">FROM</span>
    photos p
<span class="hljs-keyword">WHERE</span>
    p.filename = :filename
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span>
    p.filename
</code></pre>
<p>With this approach, if no rows are returned from the <code>tags</code> table, an empty array is created; otherwise an array of the tag values that match is returned.</p>
<p>However, I didn't know how to create this query using the Doctrine DBAL query builder.</p>
<h3>DBAL solution</h3>
<p>When creating a <code>SELECT</code> using the DBAL query builder, you do something like this:</p>
<pre><code class="language-php hljs php" data-lang="php">$select = $dbal-&gt;createQueryBuilder();
$select
    -&gt;select(
        <span class="hljs-comment">// one argument per column to select</span>
    )
    -&gt;from(<span class="hljs-string">'table_name'</span>, <span class="hljs-string">'t'</span>) <span class="hljs-comment">// alias the table</span>
</code></pre>
<p>The arguments to <code>select()</code> are expected to be strings, and any given string can be an arbitrary SQL expression.</p>
<p>Creating the subselect is easy; you do it like any other query:</p>
<pre><code class="language-php hljs php" data-lang="php">$tags = $dbal-&gt;createQueryBuilder();
$tags
    -&gt;select(<span class="hljs-string">'tag'</span>)
    -&gt;distinct()
    -&gt;from(<span class="hljs-string">'tags'</span>)
    -&gt;where(<span class="hljs-string">'content_id = p.filename'</span>)
    -&gt;andWhere(<span class="hljs-string">'content_type = :content_type'</span>);
</code></pre>
<p>Now, how do I get that into a column string for a select?</p>
<p>The <code>getSQL()</code> method of a query builder will spit out the SQL sent.
Moreover, it <strong>does not</strong> replace placeholders, so even if you set a bound parameter, it won't be injected into the generated SQL.</p>
<p>Knowing all this, I did the following:</p>
<pre><code class="language-php hljs php" data-lang="php">$tags = $dbal-&gt;createQueryBuilder();
$tags
    -&gt;select(<span class="hljs-string">'tag'</span>)
    -&gt;distinct()
    -&gt;from(<span class="hljs-string">'tags'</span>)
    -&gt;where(<span class="hljs-string">'content_id = p.filename'</span>)
    -&gt;andWhere(<span class="hljs-string">'content_type = :content_type'</span>);

$select = $dbal-&gt;createQueryBuilder();
$select
    -&gt;select(
        <span class="hljs-string">'p.filename'</span>,
        <span class="hljs-string">'p.description'</span>,
        <span class="hljs-string">'p.created'</span>,
        sprintf(<span class="hljs-string">'(SELECT ARRAY(%s)) as tags'</span>, $tags-&gt;getSQL()),
    )
    -&gt;from(<span class="hljs-string">'photos'</span>, <span class="hljs-string">'p'</span>)
    -&gt;where(<span class="hljs-string">'p.filename = :filename'</span>)
    -&gt;groupBy(<span class="hljs-string">'p.filename'</span>)
    -&gt;setParameter(<span class="hljs-string">'filename'</span>, $filename, ParameterType::STRING)
    -&gt;setParameter(<span class="hljs-string">'content_type'</span>, <span class="hljs-string">'photo'</span>, ParameterType::STRING);
</code></pre>
<p>(Where <code>ParameterType</code> is imported from the namespace <code>Doctrine\DBAL</code>.)</p>
<p>This approach worked immediately, and generated exactly the same result as the raw SQL I had tested.</p>
<h3>Changelog</h3>
<ul>
<li>2025-03-07: clarified that the solution was targeting the DBAL query builder. DBAL can consume raw SQL as well, and does not require usage of the query builder.</li>
<li>2025-03-10: noted that a <code>LEFT JOIN</code> will still work, as long as the <code>t.content_type = :content_type</code> condition is moved from the <code>SELECT</code> to the <code>LEFT JOIN</code>.</li>
</ul>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2025-03-06-dbal-sub-query.html">SQL Nested Queries or Sub Queries with Doctrine DBAL</a> was originally
    published <time class="dt-published" datetime="2025-03-06T10:35:34-06:00">6 March 2025</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>Advent 2023: Doctrine DBAL</title>
      <pubDate>Mon, 11 Dec 2023 09:21:00 -0600</pubDate>
      <link>https://mwop.net/blog/2023-12-10-advent-dbal.html</link>
      <guid>https://mwop.net/blog/2023-12-10-advent-dbal.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I've mostly taken database abstraction for granted since I started at Zend.
We had a decent abstraction layer in ZF1, and improved it for ZF2.
There were a lot quirks to it — you really had to dive in and look at the various SQL abstraction classes to understand how to do more complex stuff — but it worked, and was always right there and available in the projects I worked on.</p>
<p>In the last couple of years, though, we came to the realization in the Laminas Project that we didn't really have anybody with the expertise or time to maintain it.
We've marked it security-only twice now, and while we've managed to keep it updated to each new PHP version, it's becoming harder and harder, and whenever there's a CI issue, it's anybody's guess as to whether or not we'll be able to get it resolved.</p>
<p>My alternatives have been straight PDO, or Doctrine DBAL, with the latter being my preference.</p>


<h3>Doctrine <em>what</em>?</h3>
<p>When most folks who use PHP hear &quot;Doctrine&quot;, they immediately think &quot;<a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">ORM</a>&quot;; it's how most folks use it, and what it's best known for.</p>
<p>Underlying the ORM is its database abstraction layer (hence &quot;DBAL&quot;).
This library exposes an API that will work across any database it supports; this is essentially what zend-db, and later laminas-db, were doing as well.
What most folks don't realize is that you can use the DBAL <em>by itself</em>, without the ORM.</p>
<h3>Why no ORM?</h3>
<p>ORMs are fine.
Really.
But they add an additional layer of complexity to understanding what you are actually doing.
Additionally, if you want to do something that doesn't quite fit how the ORM works, you'll need to drop down to the DBAL anyways.
So my take has always been: why not just use the DBAL from the beginning?</p>
<p>So, how does <em>Matthew</em> write code that interacts with the database?</p>
<p>I start by writing value objects that represent discrete aspects of the application.
Most of my work will be in consuming or creating these.
From there, I write a <em><a href="https://martinfowler.com/eaaCatalog/repository.html">repository</a></em> class that I use for purposes of persisting and retrieving them.
I can usually extract an interface from this, which aids in my testing, or if I decide I need a different approach to persistence later.</p>
<p>I push the work of mapping the data from the database to these objects, and vice versa, either in the repository, or in the value objects themselves (often via a <a href="https://verraes.net/2014/06/named-constructors-in-php/">named constructor</a>).
Using these approaches creates lean code that can be easily tested, and for which there's no real need to understand the underlying system; it's all right there in what I've written for the application.</p>
<h3>Some gripes about the documentation, and some tips</h3>
<p>The <a href="https://www.doctrine-project.org/projects/doctrine-dbal/en/current/index.html">Doctrine DBAL docs</a> are a bit sparse, particularly when it comes to its <a href="https://www.doctrine-project.org/projects/doctrine-dbal/en/current/reference/query-builder.html">SQL abstraction</a>.
And there's no &quot;getting started&quot; or &quot;basic usage&quot; guide.
In fact, it's not until the third page within the docs that you get any code examples; thankfully, at that point they give you information on how to get a database connection:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-keyword">use</span> <span class="hljs-title">Doctrine</span>\<span class="hljs-title">DBAL</span>\<span class="hljs-title">DriverManager</span>;

$connectionParams = [
    <span class="hljs-string">'dbname'</span>   =&gt; <span class="hljs-string">'mydb'</span>,
    <span class="hljs-string">'user'</span>     =&gt; <span class="hljs-string">'user'</span>,
    <span class="hljs-string">'password'</span> =&gt; <span class="hljs-string">'secret'</span>,
    <span class="hljs-string">'host'</span>     =&gt; <span class="hljs-string">'localhost'</span>,
    <span class="hljs-string">'driver'</span>   =&gt; <span class="hljs-string">'pdo_mysql'</span>,
];
$conn = DriverManager::getConnection($connectionParams);
</code></pre>
<p>They also provide a number of other approaches, including using a DSN (an acronym they never explain, but based on using PDO, likely means &quot;data source name&quot;).</p>
<p>Once you have a connection, what do you do?
Well the DBAL connection allows you to prepare and execute queries, including via the use of prepared statements.
It provides a variety of methods for fetching individual or multiple rows, with a variety of options for how the data is returned (indexed arrays, associative arrays, individual columns, individual values, etc.).
These retrieval methods are mirrored in the result instances returned when executing prepared statements as well.</p>
<p>And that brings me to the SQL abstraction.</p>
<p>First, it's really, really good.
It's minimal, but it covers just about anything you need to do.
If you need to write something complex, you probably can; the beauty is that if you can't, you can always fall back to a SQL query, and using the connection's API for binding values.</p>
<p>But the documentation could be better.</p>
<p>It felt like it was written by a database admin who has forgotten more than most people ever learn about databases, and never considered that others might not know as much as them.
The fact that it starts with architecture and not usage feels hugely antagonistic for somebody coming in just wanting to know how to connect to the database, build a query, and fetch some results.
(The irony is not lost on me that this is almost exactly how Laminas and Mezzio docs are written, and, yes, I recognize we could all do better!)</p>
<blockquote>
<p>Before folks start grousing, yes, I have on my TODO list an item for contributing to the DBAL docs.
I'm trying to work up an outline of what I would have found useful, what acronyms need explanation, and some examples of common patterns before I make any suggestions, however.</p>
</blockquote>
<p>First, they have a whole documentation page related to the SQL query builder, and a lot of examples.
But not a single one details <em>how to actually execute the query</em>!
So, for those wondering:</p>
<pre><code class="language-php hljs php" data-lang="php">$sql = $conn-&gt;createQueryBuilder();

<span class="hljs-comment">// ... build your query ...</span>

<span class="hljs-comment">// Execute a query that will retrieve results (generally SELECT queries):</span>
$result = $sql-&gt;executeQuery();

<span class="hljs-comment">// Execute a query that produces changes (INSERT, UPDATE, DELETE, etc.):</span>
$count = $sql-&gt;executeStatement();
</code></pre>
<p>Query results have a variety of <code>fetch*()</code> operations on them, while executing a statement returns an integer indicating the number of rows affected (assuming the database supports this).</p>
<p>Second, when I started doing joins, the argument names were confusing, and made it harder to understand what was needed.
I eventually figured it out, but it was really easy to flip the arguments for the different tables being joined.
The usage below illustrates names that would better describe how to use it:</p>
<pre><code class="language-php hljs php" data-lang="php">$sql-&gt;innerJoin(
    $primaryTableOrItsAliasIfYouSpecifiedOne, <span class="hljs-comment">// e.g. "user" or "u"</span>
    $newTableToJoin,                          <span class="hljs-comment">// e.g. "address"</span>
    $aliasForNewTableToJoin,                  <span class="hljs-comment">// e.g. "a"</span>
    $conditionToJoinOn                        <span class="hljs-comment">// e.g. "u.id = a.uid"</span>
);
</code></pre>
<p>Third, there's some odd differences in the API between INSERT and UPDATE operations.,
When setting a value, one takes <code>setValue()</code>, while the other takes <code>set()</code>, and only one of these is valid for a given operation (it's <code>setValue()</code> for INSERT operations, and <code>set()</code> for UPDATE operations, in case you were wondering).
This is especially confusing when using bound parameters, because <em>both</em> can use the <code>setParameter()</code> method for binding positional placeholder values.</p>
<p>Speaking of plaeholders, the docs don't do a great job of detailing how to handle <em>placeholders</em> gracefully.</p>
<p>The documentation suggests patterns like this:</p>
<pre><code class="language-php hljs php" data-lang="php">$queryBuilder
    -&gt;select(<span class="hljs-string">'id'</span>, <span class="hljs-string">'name'</span>)
    -&gt;from(<span class="hljs-string">'users'</span>)
    -&gt;where(<span class="hljs-string">'email = ?'</span>)
    -&gt;setParameter(<span class="hljs-number">0</span>, $userInputEmail);
</code></pre>
<p>Which is fine when there's only one parameterized value, but what if you have several, or if you're dynamically building the query (e.g., looping through user-supplied sorting or criteria, etc.), and you don't know their exact position in the final query?
And what if you want to use named parameters instead of positional parameters, but you're not sure if your database supports them?</p>
<p>The answer is in the docs, but the various <em>examples</em> don't use the pattern (other than in the discussion of the methods), which is infuriating.
The above can also be written as follows:</p>
<pre><code class="language-php hljs php" data-lang="php">$queryBuilder
    -&gt;select(<span class="hljs-string">'id'</span>, <span class="hljs-string">'name'</span>)
    -&gt;from(<span class="hljs-string">'users'</span>)
    -&gt;where(<span class="hljs-string">'email = '</span> . $queryBuilder-&gt;createNamedParameter($userInputEmail));
</code></pre>
<p>There's also a <code>createPositionalParameter()</code> method.
Both accept an optional second argument, where you can specify the value <em>type</em>, which can help ensure that values are quoted correctly for the SQL type they will map to.
This also allows you to do <code>IN()</code> operations, and each value will be quoted correctly, with the appropriate list separator for the database.</p>
<p>Once you know this approach, it's easy to remember and use, but it took me a few times through the docs before I stumbled across it.</p>
<p>The SQL it generates, though, is great, and when I've used tools like ZendHQ's Z-Ray to introspect queries, I'm always impressed by what was actually sent over the wire.</p>
<blockquote>
<h4>2023-12-11 Update</h4>
<p><a href="https://mastodon.social/@nesl247">Alexander Kim</a> pointed out to me that you can use named parameters within the query builder, along with the <code>setParameter()</code> method.
That usage looks like this:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-keyword">use</span> <span class="hljs-title">Doctrine</span>\<span class="hljs-title">DBAL</span>\<span class="hljs-title">ParameterType</span>;

$queryBuilder
    -&gt;select(<span class="hljs-string">'id'</span>, <span class="hljs-string">'name'</span>)
    -&gt;from(<span class="hljs-string">'users'</span>)
    -&gt;where(<span class="hljs-string">'email = :email'</span>)
    -&gt;setParameter(<span class="hljs-string">'email'</span>, $userInputEmail, ParameterType::STRING);
</code></pre>
<p>You can also specify named parameters when using <code>set()</code> and <code>setValue()</code>, though I'd argue that using <code>createNamedParameter()</code> is easier in those contexts.</p>
</blockquote>
<p>But for all these issues, the fact is that the docs generally give you <em>enough</em>, and the API is so clean and reasonably documented that you can generally figure out how things work just from your IDE hints and autocompletion.
Yes, I have gripes, but the library is <em>very</em> solid, <em>very</em> well written, and absolutely something I can depend on.</p>
<h3>Final Thoughts</h3>
<p>I've often used straight PDO for projects, and it works fine.
However, having a tool available like Doctrine DBAL has been a huge boon in ensuring I can switch from SQLite while prototyping to MySQL for production, and know that things will &quot;just work&quot;.</p>
<p>I also find the way it juggles <em>types</em> to be really useful.
I know that if a value is typed in the database as a NULL or as text or as a float or integer, I'll actually get those types back when I query; the same is true for when I send data to the database.
There's no magic involved, and I don't have to remember to do type conversions to and from the database.
That's <em>exactly</em> the type of functionality I want from a DBAL.</p>
<p>Yes, writing database-centric code is cumbersome, and there's a reason folks use ORMs, ActiveRecord, and the like.
However, it generally only needs to be written once, with occasional updates.
Having a good DBAL available helps keep complexity of your application down and gives you the tools to communicate securely with your database.</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2023-12-10-advent-dbal.html">Advent 2023: Doctrine DBAL</a> was originally
    published <time class="dt-published" datetime="2023-12-10T11:00:00-06:00">10 December 2023</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
    <item>
      <title>On Visibility in OOP</title>
      <pubDate>Sat, 30 Jun 2012 10:00:00 -0500</pubDate>
      <link>https://mwop.net/blog/2012-06-28-oop-visibility.html</link>
      <guid>https://mwop.net/blog/2012-06-28-oop-visibility.html</guid>
      <author>contact@mwop.net (Matthew Weier O'Phinney)</author>
      <dc:creator>Matthew Weier O'Phinney</dc:creator>
      <content:encoded><![CDATA[<p>I'm a big proponent of object oriented programming. OOP done right helps ease
code maintenance and enables code re-use.</p>
<p>Starting in PHP, OOP enthusiasts got a whole bunch of new tools, and new tools
keep coming into the language for us with each minor release. One feature that
has had a huge impact on frameworks and libraries has been available since the
earliest PHP 5 versions: visibility.</p>


<h2>Theory</h2>
<p>The visibility keywords include <em>private</em>, <em>protected</em>, and <em>public</em>, often
referred to as <strong>PPP</strong>. There's an additional keyword I often lump in with
them, <em>final</em>.</p>
<p>Public visibility is the default, and equivalent to the only visibility
available to PHP prior to version 5: any member declared public is accessible
from any scope. This means the following:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">public</span> $bar = <span class="hljs-string">'bar'</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">baz</span><span class="hljs-params">()</span> 
    </span>{
        <span class="hljs-comment">// I can access within my own scope</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;bar;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FooBar</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doThat</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-comment">// I have access to members in my parent</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;bar . <span class="hljs-keyword">$this</span>-&gt;baz();
    }
}

$foo = <span class="hljs-keyword">new</span> Foo();

<span class="hljs-comment">// I can access public members from an instance</span>
<span class="hljs-keyword">echo</span> $foo-&gt;bar . $foo-&gt;baz();
</code></pre>
<p>Basically, public visibility means that I can access the member from within the
object, within an extending class, or from simply an instance.</p>
<p>Protected visibility starts to tighten things down a little. With protected
visibility, only the class itself, or an extending class, can access the
member:</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">protected</span> $bar = <span class="hljs-string">'bar'</span>;

    <span class="hljs-keyword">protected</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">baz</span><span class="hljs-params">()</span> 
    </span>{
        <span class="hljs-comment">// I can access within my own scope</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;bar;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FooBar</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doThat</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-comment">// I can access protected members in my parent</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;bar . <span class="hljs-keyword">$this</span>-&gt;baz();
    }
}

$foo = <span class="hljs-keyword">new</span> FooBar();

<span class="hljs-comment">// This works, as I'm calling a public member of an extending class:</span>
$foo-&gt;doThat();

<span class="hljs-comment">// But these are both illegal:</span>
<span class="hljs-keyword">echo</span> $foo-&gt;bar . $foo-&gt;baz();
</code></pre>
<p>Protected visibility is nice for hiding things from those consuming your class.
It can be used to hide implementation details, and to prevent direct
modification of public properties — something important to consider, if a
property may be the product of calculation, or if a particular type is
required.</p>
<p>Private visibility locks things down further. With private visibility, the
object member is only directly modifiable or callable within the declaring
class.</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">private</span> $bar = <span class="hljs-string">'bar'</span>;

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">baz</span><span class="hljs-params">()</span> 
    </span>{
        <span class="hljs-comment">// I can access within my own scope</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;bar;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FooBar</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">doThat</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-comment">// These are both illegal</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;bar . <span class="hljs-keyword">$this</span>-&gt;baz();
    }
}

$foo = <span class="hljs-keyword">new</span> FooBar();

<span class="hljs-comment">// These are also both illegal:</span>
<span class="hljs-keyword">echo</span> $foo-&gt;bar . $foo-&gt;baz();
</code></pre>
<p>Private visibility is generally of interest for locking down algorithms. For
instance, if you know that a particular value or operation must not change,
even in extending classes, declaring the member private ensures that extending
classes cannot directly call it.</p>
<p>At any point, you can redeclare a property in an extending class using equal or
more public visibility. The effect of doing so depends on what the visibility
of the member was in the parent class.</p>
<ul>
<li>
<p>In the case of a <em>public</em> property, if an extending class re-declares with
public visibility, any access to the member within the extending class or an
instance of the extending class will see only the new declaration.</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">public</span> $bar = <span class="hljs-string">'bar'</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">baz</span><span class="hljs-params">()</span> 
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;bar;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FooBar</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">public</span> $bar = <span class="hljs-string">'foobar'</span>;
}

$foo = <span class="hljs-keyword">new</span> FooBar();
<span class="hljs-keyword">echo</span> $foo-&gt;bar;   <span class="hljs-comment">// "foobar"</span>
<span class="hljs-keyword">echo</span> $foo-&gt;baz(); <span class="hljs-comment">// "foobar"</span>
</code></pre>
</li>
<li>
<p>In the instance of a <em>protected</em> property, if the extending class re-declares
with either public or protected visibility, you get the same behavior as
public -&gt; public.</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">protected</span> $bar = <span class="hljs-string">'bar'</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">baz</span><span class="hljs-params">()</span> 
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;bar;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FooBar</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">public</span> $bar = <span class="hljs-string">'foobar'</span>;
}

$foo = <span class="hljs-keyword">new</span> FooBar();
<span class="hljs-keyword">echo</span> $foo-&gt;bar;   <span class="hljs-comment">// "foobar"</span>
<span class="hljs-keyword">echo</span> $foo-&gt;baz(); <span class="hljs-comment">// "foobar"</span>
</code></pre>
</li>
<li>
<p>In the instance of a <em>private</em> property, things get interesting. The private
value or method will be used for any access made within code declared in the
parent class, but not overridden in the child. However, if the child class
overrides any code, the value of the re-declared instance will be used. This
is far easier to understand via an example.</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">private</span> $bar = <span class="hljs-string">'bar'</span>;
    <span class="hljs-keyword">private</span> $baz = <span class="hljs-string">'baz'</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">baz</span><span class="hljs-params">()</span> 
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;bar;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FooBar</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">protected</span> $bar = <span class="hljs-string">'foobar'</span>;
    <span class="hljs-keyword">private</span> $baz = <span class="hljs-string">'foobaz'</span>;

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myBaz</span><span class="hljs-params">()</span> 
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;bar;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">myBaz2</span><span class="hljs-params">()</span>
    </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">$this</span>-&gt;baz;
    }
}

$foo = <span class="hljs-keyword">new</span> FooBar();
<span class="hljs-keyword">echo</span> $foo-&gt;baz();    <span class="hljs-comment">// "bar"</span>
<span class="hljs-keyword">echo</span> $foo-&gt;myBaz();  <span class="hljs-comment">// "foobar"</span>
<span class="hljs-keyword">echo</span> $foo-&gt;myBaz2(); <span class="hljs-comment">// "foobaz"</span>
</code></pre>
</li>
</ul>
<p>My personal takeaway from this is:</p>
<ul>
<li>Use <em>public</em> for members that are safe for anything to call.</li>
<li>Use <em>protected</em> for anything you don't want called from instance methods, not
important to the public API (implementation details), and anything you feel
is safe for extending classes to muck about with.</li>
<li>Use <em>private</em> for any important implementation details that could adversely
affect execution if overridden by an extending class.</li>
</ul>
<p>Those paying attention will note that I skipped <em>final</em>. Actually, I saved that
for last. Marking a class or method <em>final</em> tells PHP that the class or method
may not be extended or re-declared/overridden. At all. I lump this with
visibility, because it's another way of locking down access to an API; marking
something <em>final</em> is saying, &quot;you cannot extend this&quot;, similar to using
<em>private</em>, but without even the possibility of redeclaring.</p>
<h2>Applied</h2>
<p>What got me to thinking about all this was a turn of events with Zend Framework
2. We've had an annotation parser since last summer. <a href="http://ralphschindler.com/">Ralph Schindler</a>
developed it in order to facilitate automatic discovery of injection points for
our Dependency Injection container. Classes could mark a method with the
<code>@Inject</code> annotation, and the various DI compilers would know that that method
needed to be injected.</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-keyword">use</span> <span class="hljs-title">Zend</span>\<span class="hljs-title">Di</span>\<span class="hljs-title">Definition</span>\<span class="hljs-title">Annotation</span>\<span class="hljs-title">Inject</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-keyword">protected</span> $bar;

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@Inject</span>()
     * <span class="hljs-doctag">@param</span>  Bar $bar
     * <span class="hljs-doctag">@return</span> void
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setBar</span><span class="hljs-params">(Bar $bar)</span>
    </span>{
        <span class="hljs-keyword">$this</span>-&gt;bar = $bar;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Bar</span> </span>{}
</code></pre>
<p>Recently, part of our Forms RFC included a feature to allow creating forms and
their related input filters by using annotations. Basically, this allows
developers to hint on their domain entities how specific properties should be
filtered, validated, and potentially represented at the form level.</p>
<pre><code class="language-php hljs php" data-lang="php"><span class="hljs-keyword">use</span> <span class="hljs-title">Zend</span>\<span class="hljs-title">Form</span>\<span class="hljs-title">Annotation</span>;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Foo</span>
</span>{
    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@Annotation</span>\Filter({"name":"StringTrim"})
     * <span class="hljs-doctag">@Annotation</span>\Validator({"name":"Between","options":{"min":5,"max":20}})
     * <span class="hljs-doctag">@Annotation</span>\Attributes({"type":"range"})
     */</span>
    <span class="hljs-keyword">protected</span> $bar;
}
</code></pre>
<p>One developer testing the support wanted to use a combination of
<a href="http://doctrine-project.org">Doctrine</a> annotations and ZF2 form annotations —
that way his entities could also describe validation and representation.</p>
<p>I did some work to make this happen, and everybody was happy. Except then that
same developer went to use that entity with Doctrine, and Doctrine's annotation
parser started raising exceptions on all the ZF2 annotations.</p>
<p>After some debate, I realized: (a) we were basically just making up syntax for
our annotations; it'd be better to use an established syntax; but (b) we should
still retain the ability to use arbitrary syntax, as we can't really know what
sorts of annotations developers may already be using.</p>
<p>So, we decided to make our annotation component depend on the annotations
support in <code>Doctrine\Common</code>, and to use the annotation syntax they utilize. ZF2
would provide some code to make it possible to plug in arbitrary parsers, and
use the <code>Doctrine\Common</code> annotation parser to parse annotations officially
supported by ZF2.</p>
<p>However, when I went to start making this happen, I ran into immediate issues.</p>
<p>Remember how this post is about visibility? Well, the class I was directly
interested in, <code>Doctrine\Common\Annotations\DocParser</code>, not only contains
private members, but is marked <em>final</em>.</p>
<p>My immediate response was to start dissecting the class, cutting and pasting
the bits interesting to my solution into a new class in ZF2. I went down this
route for several hours, gradually pulling in more and more methods as I
discovered how far down the rabbit hole I needed to go to accomplish my task.</p>
<p>But at the back of my head, I kept thinking this was a bad idea. If any patches
ever came in for the original class, I'd need to port them into our ZF2
solution. And I couldn't help but think that I'd miss a crucial piece.</p>
<p>So I started playing with its public API, to see if there were any shortcuts I
might be able to take. And there were.</p>
<p>The class has a public <code>parse()</code> method. Based on how Doctrine uses the code, I
assumed I needed to pass a full PHP docblock in — which ran counter to how I
wanted to use the code. I wanted to pass in an annotation at a time. But when I
looked closer, I realized that the parser didn't require a full docblock; any
fragment would do.</p>
<p>To make a long story short: I was able to feed the parser a single annotation
at a time from ZF2's <code>AnnotationScanner</code>. This allowed me to build a very
simple class that allows registering a set of annotations it can handle, and
feeding it a single annotation string at a time to decide (a) if it supports
it, and (b) to parse it and return the associated annotation object.</p>
<p>In sum: because the class in question was marked final and had private members,
I found myself forced to think critically about what I wanted to accomplish,
and then thoroughly understand the public API to see how I might accomplish
that task without the ability to extend.</p>
<h2>Conclusions</h2>
<p>Doctrine has a policy that encourages
<a href="http://en.wikipedia.org/wiki/Poka-yoke"><em>poka-yoke</em></a> solutions: code should be
executable in a specific way. The policy was developed to both aid users
(having multiple ways of doing something is often confusing), as well as to
ease maintenance (fewer extension points means less liklihood of developers
doing hard-to-debug things in extending code and reporting it back to the
project). These have led them to heavily use <em>private</em> and <em>final</em> visibility.</p>
<p>I've said it before, and I'll say it again: I feel that frameworks and
libraries should use <em>private</em> and <em>final</em> sparingly. Over the years, I've seen
code repurposed in simply wondrous ways — largely due to keeping the code as
open as possible to extension. I like to enable my users as much as possible.</p>
<p>That said, I can also see Doctrine's argument — and can see where, while it can
often be frustrating, it can also lead to potentially more sound and elegant
solutions.</p>
<p>I'll probably continue shying away from <em>private</em> and <em>final</em> visibility, but I
do plan to experiment with it more in the future. What about you?</p>


<div class="h-entry">
    <img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&u=79dd2ea1d4d8855944715d09ee4c86215027fa80&s=140" alt="matthew">
    <a class="u-url u-uid p-name" href="https://mwop.net/blog/2012-06-28-oop-visibility.html">On Visibility in OOP</a> was originally
    published <time class="dt-published" datetime="2012-06-28T21:20:00-05:00">28 June 2012</time>
    on <a href="https://mwop.net">https://mwop.net</a> by
    <a rel="author" class="p-author" href="https://mwop.net">Matthew Weier O&#039;Phinney</a>.
</div>
]]></content:encoded>
      <slash:comments>0</slash:comments>
    </item>
  </channel>
</rss>
