Completed
Pull Request — master (#4)
by mw
18:43 queued 17:12
created

LoggableContainerBuilder::create()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 13
cts 13
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 12
nc 4
nop 1
crap 3
1
<?php
2
3
namespace Onoi\CallbackContainer;
4
5
use Closure;
6
use Psr\Log\LoggerInterface;
7
use Psr\Log\LoggerAwareInterface;
8
9
/**
10
 * @license GNU GPL v2+
11
 * @since 2.0
12
 *
13
 * @author mwjames
14
 */
15
class LoggableContainerBuilder implements ContainerBuilder, LoggerAwareInterface {
16
17
	/**
18
	 * @var ContainerBuilder
19
	 */
20
	private $containerBuilder;
21
22
	/**
23
	 * @var BacktraceSniffer|null
24
	 */
25
	private $backtraceSniffer;
26
27
	/**
28
	 * @var CallFuncMemorySniffer|null
29
	 */
30
	private $callFuncMemorySniffer;
31
32
	/**
33
	 * @var array
34
	 */
35
	private $logs = array();
36
37
	/**
38
	 * @var loggerInterface
39
	 */
40
	private $logger;
41
42
	/**
43
	 * @since 2.0
44
	 *
45
	 * @param ContainerBuilder $containerBuilder
46
	 * @param BacktraceSniffer|null $backtraceSniffer
47
	 * @param CallFuncMemorySniffer|null $backtraceSniffer
48
	 */
49 3
	public function __construct( ContainerBuilder $containerBuilder, BacktraceSniffer $backtraceSniffer = null, CallFuncMemorySniffer $callFuncMemorySniffer = null ) {
50 3
		$this->containerBuilder = $containerBuilder;
51 3
		$this->backtraceSniffer = $backtraceSniffer;
52 3
		$this->callFuncMemorySniffer = $callFuncMemorySniffer;
53 3
	}
54
55
	/**
56
	 * @see LoggerAwareInterface::setLogger
57
	 *
58
	 * @since 2.5
59
	 *
60
	 * @param LoggerInterface $logger
61
	 */
62 2
	public function setLogger( LoggerInterface $logger ) {
63 2
		$this->logger = $logger;
0 ignored issues
show
Documentation Bug introduced by
It seems like $logger of type object<Psr\Log\LoggerInterface> is incompatible with the declared type object<Onoi\CallbackContainer\loggerInterface> of property $logger.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
64 2
	}
65
66
	/**
67
	 * @since 2.0
68
	 *
69
	 * {@inheritDoc}
70
	 */
71
	public function registerCallbackContainer( CallbackContainer $callbackContainer ) {
72
		$this->containerBuilder->registerCallbackContainer( $callbackContainer );
73
	}
74
75
	/**
76
	 * @since 2.0
77
	 *
78
	 * {@inheritDoc}
79
	 */
80 1
	public function registerCallback( $serviceName, Closure $callback ) {
81 1
		$this->containerBuilder->registerCallback( $serviceName, $callback );
82 1
	}
83
84
	/**
85
	 * @since 2.0
86
	 *
87
	 * {@inheritDoc}
88
	 */
89
	public function registerExpectedReturnType( $serviceName, $type ) {
90
		$this->containerBuilder->registerExpectedReturnType( $serviceName, $type );
91
	}
92
93
	/**
94
	 * @since 2.0
95
	 *
96
	 * {@inheritDoc}
97
	 */
98
	public function registerObject( $serviceName, $instance ) {
99
		$this->containerBuilder->registerObject( $serviceName, $instance );
100
	}
101
102
	/**
103
	 * @since 2.0
104
	 *
105
	 * {@inheritDoc}
106
	 */
107 1
	public function registerFromFile( $file ) {
108 1
		$this->containerBuilder->registerFromFile( $file );
109 1
	}
110
111
	/**
112
	 * @since 2.0
113
	 *
114
	 * {@inheritDoc}
115
	 */
116
	public function isRegistered( $serviceName ) {
117
		return $this->containerBuilder->isRegistered( $serviceName );
118
	}
119
120
	/**
121
	 * @since  2.0
122
	 *
123
	 * {@inheritDoc}
124
	 */
125 2
	public function create( $serviceName ) {
126
127 2
		$this->initLog( $serviceName );
128 2
		$this->logs[$serviceName]['prototype']++;
129
130 2
		if ( $this->backtraceSniffer !== null ) {
131 1
			$this->logs[$serviceName]['prototype-backtrace'][] = $this->backtraceSniffer->getCallers();
132 1
		}
133
134 2
		if ( $this->callFuncMemorySniffer !== null ) {
135 1
			$instance = $this->callFuncMemorySniffer->call( array( $this->containerBuilder, 'create' ), func_get_args() );
136 1
			$this->logs[$serviceName]['prototype-memory'][] = $this->callFuncMemorySniffer->getMemoryUsed();
137 1
			$this->logs[$serviceName]['prototype-time'][] = $this->callFuncMemorySniffer->getTimeUsed();
138 1
		} else {
139 1
			$instance = call_user_func_array( array( $this->containerBuilder, 'create' ), func_get_args() );
140
		}
141
142 2
		return $instance;
143
	}
144
145
	/**
146
	 * @since  2.0
147
	 *
148
	 * {@inheritDoc}
149
	 */
150 2
	public function singleton( $serviceName ) {
151
152 2
		$this->initLog( $serviceName );
153 2
		$this->logs[$serviceName]['singleton']++;
154
155 2
		if ( $this->callFuncMemorySniffer !== null ) {
156 1
			$instance = $this->callFuncMemorySniffer->call( array( $this->containerBuilder, 'singleton' ), func_get_args() );
157 1
			$this->logs[$serviceName]['singleton-memory'][] = $this->callFuncMemorySniffer->getMemoryUsed();
158 1
			$this->logs[$serviceName]['singleton-time'][] = $this->callFuncMemorySniffer->getTimeUsed();
159 1
		} else {
160 1
			$instance = call_user_func_array( array( $this->containerBuilder, 'singleton' ), func_get_args() );
161
		}
162
163 2
		return $instance;
164
	}
165
166 2
	private function initLog( $serviceName ) {
167
168 2
		if ( isset( $this->logs[$serviceName] ) ) {
169 2
			return;
170
		}
171
172 2
		$this->logs[$serviceName] = array(
173 2
			'prototype' => 0,
174 2
			'prototype-backtrace' => array(),
175 2
			'prototype-memory' => array(),
176 2
			'prototype-time' => array(),
177 2
			'singleton' => 0,
178 2
			'singleton-memory' => array(),
179 2
			'singleton-time' => array(),
180
		);
181
182 2
		if ( $this->backtraceSniffer === null ) {
183 1
			unset( $this->logs[$serviceName]['prototype-backtrace'] );
184 1
		}
185
186 2
		if ( $this->callFuncMemorySniffer === null ) {
187 1
			unset( $this->logs[$serviceName]['prototype-memory'] );
188 1
			unset( $this->logs[$serviceName]['singleton-memory'] );
189 1
			unset( $this->logs[$serviceName]['prototype-time'] );
190 1
			unset( $this->logs[$serviceName]['singleton-time'] );
191 1
		}
192 2
	}
193
194 3
	function __destruct() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for __destruct.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
195
196
		// Build median
197 3
		foreach ( $this->logs as $serviceName => $record ) {
198
199 2
			$count = $this->logs[$serviceName]['singleton'];
200 2
			$this->calcMedian( 'singleton-memory', $serviceName, $record,$count );
201 2
			$this->calcMedian( 'singleton-time', $serviceName, $record, $count );
202
203 2
			$count = $this->logs[$serviceName]['prototype'];
204 2
			$this->calcMedian( 'prototype-memory', $serviceName, $record, $count );
205 2
			$this->calcMedian( 'prototype-time', $serviceName, $record, $count );
206 3
		}
207
208 3
		$this->log( json_encode( $this->logs, JSON_PRETTY_PRINT ) );
209 3
	}
210
211 2
	private function calcMedian( $type, $serviceName, $record, $count ) {
212 2
		if ( isset( $record[$type] ) && $count > 0 ) {
213 1
			$this->logs[$serviceName][$type . '-median'] = array_sum( $record[$type] ) / $count;
214 1
			unset( $this->logs[$serviceName][$type] );
215 1
		}
216 2
	}
217
218 3
	private function log( $message, $context = array() ) {
219
220 3
		if ( $this->logger === null ) {
221 1
			return;
222
		}
223
224 2
		$this->logger->info( $message, $context );
225 2
	}
226
227
}
228