I’m working on several projects right now that I’d like to be able to generate logs from.
The problem is that logging isn’t required for the code to work, so how do I configure it?
I see three possibilities:
Required in Constructor
<span class="token keyword">use</span> <span class="token package">Psr<span class="token punctuation">\</span>Log<span class="token punctuation">\</span>LoggerInterface</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name-definition class-name">MyClass</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token variable">$logger</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span><span class="token class-name type-declaration">LoggerInterface</span> <span class="token variable">$logger</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
Pros
- Cleanest implementation
Cons
- Requires user to pass in a logger even if they don’t want to log anything
Optional in Constructor
<span class="token keyword">use</span> <span class="token package">Psr<span class="token punctuation">\</span>Log<span class="token punctuation">\</span>LoggerInterface</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Psr<span class="token punctuation">\</span>Log<span class="token punctuation">\</span>NullLogger</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name-definition class-name">MyClass</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token variable">$logger</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span><span class="token class-name type-declaration">LoggerInterface</span> <span class="token variable">$logger</span> <span class="token operator">=</span> <span class="token constant">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">is_null</span><span class="token punctuation">(</span><span class="token variable">$logger</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
<span class="token variable">$this</span><span class="token operator">-></span><span class="token property">logger</span> <span class="token operator">=</span> <span class="token variable">$logger</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
Pros
- No longer requires the user to pass in a logger
Cons
- Clutters up the constructor
- I consider using null a code smell
Optional setLogger Method
<span class="token keyword">use</span> <span class="token package">Psr<span class="token punctuation">\</span>Log<span class="token punctuation">\</span>LoggerInterface</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token package">Psr<span class="token punctuation">\</span>Log<span class="token punctuation">\</span>NullLogger</span><span class="token punctuation">;</span>
<span class="token keyword">class</span> <span class="token class-name-definition class-name">MyClass</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token variable">$logger</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">setLogger</span><span class="token punctuation">(</span><span class="token class-name type-declaration">LoggerInterface</span> <span class="token variable">$logger</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
Pros
- Clean constructor
- No nulls
Cons
- Instantiating with a logger requires two statements
Summary
I’m leaning toward the third method for my packages even though it doesn’t feel like an ideal solution. It just feels better than the other two.
How are you handling injecting an optional logger? Let me know in the comments.