Completed
Pull Request — master (#4)
by mw
10:59
created

LoggableContainerBuilder   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 213
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 24
lcom 1
cbo 3
dl 0
loc 213
rs 10
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A setLogger() 0 3 1
A registerCallbackContainer() 0 3 1
A registerCallback() 0 3 1
A registerExpectedReturnType() 0 3 1
A registerObject() 0 3 1
A registerFromFile() 0 3 1
A isRegistered() 0 3 1
A create() 0 19 3
A singleton() 0 15 2
B initLog() 0 27 4
A __destruct() 0 16 2
A calcMedian() 0 6 3
A log() 0 8 2
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
	public function __construct( ContainerBuilder $containerBuilder, BacktraceSniffer $backtraceSniffer = null, CallFuncMemorySniffer $callFuncMemorySniffer = null ) {
50
		$this->containerBuilder = $containerBuilder;
51
		$this->backtraceSniffer = $backtraceSniffer;
52
		$this->callFuncMemorySniffer = $callFuncMemorySniffer;
53
	}
54
55
	/**
56
	 * @see LoggerAwareInterface::setLogger
57
	 *
58
	 * @since 2.5
59
	 *
60
	 * @param LoggerInterface $logger
61
	 */
62
	public function setLogger( LoggerInterface $logger ) {
63
		$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
	}
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
	public function registerCallback( $serviceName, Closure $callback ) {
81
		$this->containerBuilder->registerCallback( $serviceName, $callback );
82
	}
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
	public function registerFromFile( $file ) {
108
		$this->containerBuilder->registerFromFile( $file );
109
	}
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
	public function create( $serviceName ) {
126
127
		$this->initLog( $serviceName );
128
		$this->logs[$serviceName]['prototype']++;
129
130
		if ( $this->backtraceSniffer !== null ) {
131
			$this->logs[$serviceName]['prototype-backtrace'][] = $this->backtraceSniffer->getCallers();
132
		}
133
134
		if ( $this->callFuncMemorySniffer !== null ) {
135
			$instance = $this->callFuncMemorySniffer->call( array( $this->containerBuilder, 'create' ), func_get_args() );
136
			$this->logs[$serviceName]['prototype-memory'][] = $this->callFuncMemorySniffer->getMemoryUsed();
137
			$this->logs[$serviceName]['prototype-time'][] = $this->callFuncMemorySniffer->getTimeUsed();
138
		} else {
139
			$instance = call_user_func_array( array( $this->containerBuilder, 'create' ), func_get_args() );
140
		}
141
142
		return $instance;
143
	}
144
145
	/**
146
	 * @since  2.0
147
	 *
148
	 * {@inheritDoc}
149
	 */
150
	public function singleton( $serviceName ) {
151
152
		$this->initLog( $serviceName );
153
		$this->logs[$serviceName]['singleton']++;
154
155
		if ( $this->callFuncMemorySniffer !== null ) {
156
			$instance = $this->callFuncMemorySniffer->call( array( $this->containerBuilder, 'singleton' ), func_get_args() );
157
			$this->logs[$serviceName]['singleton-memory'][] = $this->callFuncMemorySniffer->getMemoryUsed();
158
			$this->logs[$serviceName]['singleton-time'][] = $this->callFuncMemorySniffer->getTimeUsed();
159
		} else {
160
			$instance = call_user_func_array( array( $this->containerBuilder, 'singleton' ), func_get_args() );
161
		}
162
163
		return $instance;
164
	}
165
166
	private function initLog( $serviceName ) {
167
168
		if ( isset( $this->logs[$serviceName] ) ) {
169
			return;
170
		}
171
172
		$this->logs[$serviceName] = array(
173
			'prototype' => 0,
174
			'prototype-backtrace' => array(),
175
			'prototype-memory' => array(),
176
			'prototype-time' => array(),
177
			'singleton' => 0,
178
			'singleton-memory' => array(),
179
			'singleton-time' => array(),
180
		);
181
182
		if ( $this->backtraceSniffer === null ) {
183
			unset( $this->logs[$serviceName]['prototype-backtrace'] );
184
		}
185
186
		if ( $this->callFuncMemorySniffer === null ) {
187
			unset( $this->logs[$serviceName]['prototype-memory'] );
188
			unset( $this->logs[$serviceName]['singleton-memory'] );
189
			unset( $this->logs[$serviceName]['prototype-time'] );
190
			unset( $this->logs[$serviceName]['singleton-time'] );
191
		}
192
	}
193
194
	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
		foreach ( $this->logs as $serviceName => $record ) {
198
199
			$count = $this->logs[$serviceName]['singleton'];
200
			$this->calcMedian( 'singleton-memory', $serviceName, $record,$count );
201
			$this->calcMedian( 'singleton-time', $serviceName, $record, $count );
202
203
			$count = $this->logs[$serviceName]['prototype'];
204
			$this->calcMedian( 'prototype-memory', $serviceName, $record, $count );
205
			$this->calcMedian( 'prototype-time', $serviceName, $record, $count );
206
		}
207
208
		$this->log( json_encode( $this->logs, JSON_PRETTY_PRINT ) );
209
	}
210
211
	private function calcMedian( $type, $serviceName, $record, $count ) {
212
		if ( isset( $record[$type] ) && $count > 0 ) {
213
			$this->logs[$serviceName][$type . '-median'] = array_sum( $record[$type] ) / $count;
214
			unset( $this->logs[$serviceName][$type] );
215
		}
216
	}
217
218
	private function log( $message, $context = array() ) {
219
220
		if ( $this->logger === null ) {
221
			return;
222
		}
223
224
		$this->logger->info( $message, $context );
225
	}
226
227
}
228