Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>This is mostly a summary of (my perspective of) <a href="http://chat.stackoverflow.com/rooms/6954/discussion-between-zerkms-and-deceze">the chat that ensued between me and @zerkms</a>:</p> <p>The point of contention is actually this:</p> <pre><code>public function doSomething($id) { $user = User::getByPhone($this-&gt;pdo, $id); // do something with user return $someData; } </code></pre> <p>This makes it hard to test <code>doSomething</code> since it hardcodes the <code>User</code> class, which may or may not have a lot of dependencies. But this is in fact the same as instantiating the object using a non-static method:</p> <pre><code>public function doSomething($id) { $user = new User; $user-&gt;initializeFromDb($this-&gt;pdo, $id); // do something with user return $someData; } </code></pre> <p>We're not using a static method, but it's still unmockable. Actually, it got worse.<br> The answer is to use a factory:</p> <pre><code>public function doSomething($id) { $user = $this-&gt;UserFactory-&gt;byPhone($id); // do something with user return $someData; } </code></pre> <p>Now the factory can be dependency injected and mocked and the <code>User</code> class is no longer hardcoded. You may or may not think this overkill, but it certainly improves mockability.</p> <p>That does not change the fact though that this factory may very well instantiate the actual user object using a static method:</p> <pre><code>public function byPhone($id) { return User::getByPhone($this-&gt;db, $id); } </code></pre> <p>There's no difference between using a static method or a regular constructor here.</p> <pre><code>$user = new User($db, $id); $user = User::getByPhone($db, $id); </code></pre> <p>Both expressions return an instance of <code>User</code> and both "hardcode" the <code>User</code> class. Which simply needs to happen at some point anyway.</p> <p>For my use case, a <code>static</code> constructor method makes the most sense for the object. And as was demonstrated, <code>static</code> methods are not the problem. Where to <em>call</em> them is the point of contention, not that they exist at all. And I have yet to see a convincing argument for not using static constructors, since they can be wrapped in a factory, which alleviates any problem with mockability, the same as it does for regular object instantiation.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. COFor `User::getByPhone()` to have a dependency (like a `PDO` connection) that isn't injected through a method argument, it has to *maintain some sort of state*. Static methods only cause problems when you allow them to maintain/use state. As long as your static methods do not do this, then testability is not affected whatsoever. Please see my answer.
      singulars
    2. CO@drrcknlsn That is true, **but**: static methods cannot be mocked. Even if they're 100% dependency injected and the dependencies can be mocked, the static method itself cannot be mocked. This may be important if the method is doing a lot of work or the (injected) dependencies are so extensive that they're difficult to mock. In that case it can be a lot easier to just mock the method itself, which makes it easier to test code *that uses this method*. That is all true. Only **object construction** using a static method is a special case, which does not affect mockability.
      singulars
    3. COAfter some abstinence I had a good long look at all the answers here again. Unfortunately none really address the issue I posed in the question, which is about static constructors and why they're bad for testability. I hate to do so with all the good things written by others here, but I'll accept my own answer on this. I have also worked this issue into an article: [How Not To Kill Your Testability Using Statics](http://kunststube.net/static/).
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload