Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Firstly, the DateTime class was a good (tricky) class to choose because it is a horrible class. All of its important work is done in the constructor and there is no way to set the date/time after it has been constructed. This requires us to have an objectGenerator that can build the DateTime object at the correct time. We can still manage this without calling new in the User class though.</p> <p>I have kept things very simple to solve the problem at hand, but they can be extended easily to handle an arbitrarily complex problem.</p> <p>Here is a simple objectGenerator to remove the coupling you get with <code>new</code>.</p> <pre><code> class ObjectGenerator { public function getNew($className) { return new $className; } } </code></pre> <p>Now we inject all of the dependencies into the constructor. The constructor shouldn't do real work, only set up the object.</p> <pre><code>class User { private $phone, $status = 'default', $created, $modified, $pdo, $objectGenerator; public function __construct(PDO $pdo, $objectGenerator) { $this-&gt;pdo = $pdo; $this-&gt;objectGenerator = $objectGenerator; $this-&gt;created = $this-&gt;objectGenerator-&gt;getNew('DateTime'); } public function createNew() { $this-&gt;phone = ''; $this-&gt;status = 'default'; $this-&gt;created = $this-&gt;objectGenerator-&gt;getNew('DateTime'); } public function selectByPhone($phone) { $stmt = $this-&gt;pdo-&gt;prepare('SELECT * FROM `users` WHERE `phone` = :phone'); $stmt-&gt;execute(compact('phone')); if (!$stmt-&gt;rowCount()) { return false; } $record = $stmt-&gt;fetch(PDO::FETCH_ASSOC); $this-&gt;phone = $record['phone']; $this-&gt;status = $record['status']; $this-&gt;created = $record['created']; $this-&gt;modified = $record['modified']; } public function setPhone($phone) { $this-&gt;phone = $phone; } public function setStatus($status) { $this-&gt;status = $status; } public function save() { $stmt = $this-&gt;pdo-&gt;prepare( 'INSERT INTO `users` (`phone`, `status`, `created`, `modified`) VALUES (:phone, :status, :created, :modified) ON DUPLICATE KEY UPDATE `status` = :status, `modified` = :modified'); $modified = $this-&gt;objectGenerator-&gt;getNew('DateTime'); $data = array( 'phone' =&gt; $this-&gt;phone, 'status' =&gt; $this-&gt;status, 'created' =&gt; $this-&gt;created-&gt;format('Y-m-d H:i:s'), 'modified' =&gt; $modified-&gt;format('Y-m-d H:i:s') ); return $stmt-&gt;execute($data); } } </code></pre> <p>Usage:</p> <pre><code>$objectGenerator = new ObjectGenerator(); $pdo = new PDO(); // OR $pdo = $objectGenerator-&gt;getNew('PDO'); $user = new User($pdo, $objectGenerator); $user-&gt;setPhone('123456789'); $user-&gt;save(); $user-&gt;selectByPhone('5555555'); $user-&gt;setPhone('5552222'); $user-&gt;save(); </code></pre> <p>So, <strong>no new or static in the user class</strong>. Try testing both solutions. The test code is a pleasure to write without the calls to new. All classes that use the User will also be easy to test without static calls to it.</p> <p>The differences in test code are:</p> <p><strong>new/static</strong> - Require a stub for each new or static call to stop the unit from reaching outside of itself.</p> <p><strong>dependency injection</strong> - Mock objects can be injected. It is painless.</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. This table or related slice is empty.
    1. This table or related slice is empty.
 

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