|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/* |
|
4
|
|
|
* This file is part of the league/commonmark package. |
|
5
|
|
|
* |
|
6
|
|
|
* (c) Colin O'Dell <[email protected]> |
|
7
|
|
|
* |
|
8
|
|
|
* Original code based on the CommonMark JS reference parser (https://bitly.com/commonmark-js) |
|
9
|
|
|
* - (c) John MacFarlane |
|
10
|
|
|
* |
|
11
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
12
|
|
|
* file that was distributed with this source code. |
|
13
|
|
|
*/ |
|
14
|
|
|
|
|
15
|
|
|
namespace League\CommonMark; |
|
16
|
|
|
|
|
17
|
|
|
use League\CommonMark\Block\Parser\BlockParserInterface; |
|
18
|
|
|
use League\CommonMark\Block\Renderer\BlockRendererInterface; |
|
19
|
|
|
use League\CommonMark\Delimiter\Processor\DelimiterProcessorCollection; |
|
20
|
|
|
use League\CommonMark\Delimiter\Processor\DelimiterProcessorInterface; |
|
21
|
|
|
use League\CommonMark\Event\AbstractEvent; |
|
22
|
|
|
use League\CommonMark\Extension\CommonMarkCoreExtension; |
|
23
|
|
|
use League\CommonMark\Extension\ExtensionInterface; |
|
24
|
|
|
use League\CommonMark\Extension\GithubFlavoredMarkdownExtension; |
|
25
|
|
|
use League\CommonMark\Inline\Parser\InlineParserInterface; |
|
26
|
|
|
use League\CommonMark\Inline\Renderer\InlineRendererInterface; |
|
27
|
|
|
use League\CommonMark\Util\Configuration; |
|
28
|
|
|
use League\CommonMark\Util\ConfigurationAwareInterface; |
|
29
|
|
|
use League\CommonMark\Util\PrioritizedList; |
|
30
|
|
|
|
|
31
|
|
|
final class Environment implements ConfigurableEnvironmentInterface |
|
32
|
|
|
{ |
|
33
|
|
|
/** |
|
34
|
|
|
* @var ExtensionInterface[] |
|
35
|
|
|
*/ |
|
36
|
|
|
private $extensions = []; |
|
37
|
|
|
|
|
38
|
|
|
/** |
|
39
|
|
|
* @var ExtensionInterface[] |
|
40
|
|
|
*/ |
|
41
|
|
|
private $uninitializedExtensions = []; |
|
42
|
|
|
|
|
43
|
|
|
/** |
|
44
|
|
|
* @var bool |
|
45
|
|
|
*/ |
|
46
|
|
|
private $extensionsInitialized = false; |
|
47
|
|
|
|
|
48
|
|
|
/** |
|
49
|
|
|
* @var PrioritizedList<BlockParserInterface> |
|
50
|
|
|
*/ |
|
51
|
|
|
private $blockParsers; |
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* @var PrioritizedList<InlineParserInterface> |
|
55
|
|
|
*/ |
|
56
|
|
|
private $inlineParsers; |
|
57
|
|
|
|
|
58
|
|
|
/** |
|
59
|
|
|
* @var array<string, PrioritizedList<InlineParserInterface>> |
|
60
|
|
|
*/ |
|
61
|
|
|
private $inlineParsersByCharacter = []; |
|
62
|
|
|
|
|
63
|
|
|
/** |
|
64
|
|
|
* @var DelimiterProcessorCollection |
|
65
|
|
|
*/ |
|
66
|
|
|
private $delimiterProcessors; |
|
67
|
|
|
|
|
68
|
|
|
/** |
|
69
|
|
|
* @var array<string, PrioritizedList<BlockRendererInterface>> |
|
70
|
|
|
*/ |
|
71
|
|
|
private $blockRenderersByClass = []; |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* @var array<string, PrioritizedList<InlineRendererInterface>> |
|
75
|
|
|
*/ |
|
76
|
|
|
private $inlineRenderersByClass = []; |
|
77
|
|
|
|
|
78
|
|
|
/** |
|
79
|
|
|
* @var array<string, PrioritizedList<callable>> |
|
80
|
|
|
*/ |
|
81
|
|
|
private $listeners = []; |
|
82
|
|
|
|
|
83
|
|
|
/** |
|
84
|
|
|
* @var Configuration |
|
85
|
|
|
*/ |
|
86
|
|
|
private $config; |
|
87
|
|
|
|
|
88
|
|
|
/** |
|
89
|
|
|
* @var string |
|
90
|
|
|
*/ |
|
91
|
|
|
private $inlineParserCharacterRegex; |
|
92
|
|
|
|
|
93
|
2619 |
|
public function __construct(array $config = []) |
|
94
|
|
|
{ |
|
95
|
2619 |
|
$this->config = new Configuration($config); |
|
96
|
|
|
|
|
97
|
2619 |
|
$this->blockParsers = new PrioritizedList(); |
|
98
|
2619 |
|
$this->inlineParsers = new PrioritizedList(); |
|
99
|
2619 |
|
$this->delimiterProcessors = new DelimiterProcessorCollection(); |
|
100
|
2619 |
|
} |
|
101
|
|
|
|
|
102
|
|
|
/** |
|
103
|
|
|
* {@inheritdoc} |
|
104
|
|
|
*/ |
|
105
|
2478 |
|
public function mergeConfig(array $config = []) |
|
106
|
|
|
{ |
|
107
|
2478 |
|
$this->assertUninitialized('Failed to modify configuration.'); |
|
108
|
|
|
|
|
109
|
2475 |
|
$this->config->merge($config); |
|
110
|
2475 |
|
} |
|
111
|
|
|
|
|
112
|
|
|
/** |
|
113
|
|
|
* {@inheritdoc} |
|
114
|
|
|
*/ |
|
115
|
6 |
|
public function setConfig(array $config = []) |
|
116
|
|
|
{ |
|
117
|
6 |
|
$this->assertUninitialized('Failed to modify configuration.'); |
|
118
|
|
|
|
|
119
|
3 |
|
$this->config->replace($config); |
|
120
|
3 |
|
} |
|
121
|
|
|
|
|
122
|
|
|
/** |
|
123
|
|
|
* {@inheritdoc} |
|
124
|
|
|
*/ |
|
125
|
2481 |
|
public function getConfig($key = null, $default = null) |
|
126
|
|
|
{ |
|
127
|
2481 |
|
return $this->config->get($key, $default); |
|
128
|
|
|
} |
|
129
|
|
|
|
|
130
|
|
|
/** |
|
131
|
|
|
* {@inheritdoc} |
|
132
|
|
|
*/ |
|
133
|
2475 |
|
public function addBlockParser(BlockParserInterface $parser, int $priority = 0): ConfigurableEnvironmentInterface |
|
134
|
|
|
{ |
|
135
|
2475 |
|
$this->assertUninitialized('Failed to add block parser.'); |
|
136
|
|
|
|
|
137
|
2472 |
|
$this->blockParsers->add($parser, $priority); |
|
138
|
2472 |
|
$this->injectEnvironmentAndConfigurationIfNeeded($parser); |
|
139
|
|
|
|
|
140
|
2472 |
|
return $this; |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
/** |
|
144
|
|
|
* {@inheritdoc} |
|
145
|
|
|
*/ |
|
146
|
2478 |
|
public function addInlineParser(InlineParserInterface $parser, int $priority = 0): ConfigurableEnvironmentInterface |
|
147
|
|
|
{ |
|
148
|
2478 |
|
$this->assertUninitialized('Failed to add inline parser.'); |
|
149
|
|
|
|
|
150
|
2475 |
|
$this->inlineParsers->add($parser, $priority); |
|
151
|
2475 |
|
$this->injectEnvironmentAndConfigurationIfNeeded($parser); |
|
152
|
|
|
|
|
153
|
2475 |
|
foreach ($parser->getCharacters() as $character) { |
|
154
|
2472 |
|
if (!isset($this->inlineParsersByCharacter[$character])) { |
|
155
|
2472 |
|
$this->inlineParsersByCharacter[$character] = new PrioritizedList(); |
|
156
|
|
|
} |
|
157
|
|
|
|
|
158
|
2472 |
|
$this->inlineParsersByCharacter[$character]->add($parser, $priority); |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
2475 |
|
return $this; |
|
162
|
|
|
} |
|
163
|
|
|
|
|
164
|
|
|
/** |
|
165
|
|
|
* {@inheritdoc} |
|
166
|
|
|
*/ |
|
167
|
2475 |
|
public function addDelimiterProcessor(DelimiterProcessorInterface $processor): ConfigurableEnvironmentInterface |
|
168
|
|
|
{ |
|
169
|
2475 |
|
$this->assertUninitialized('Failed to add delimiter processor.'); |
|
170
|
2472 |
|
$this->delimiterProcessors->add($processor); |
|
171
|
2472 |
|
$this->injectEnvironmentAndConfigurationIfNeeded($processor); |
|
172
|
|
|
|
|
173
|
2472 |
|
return $this; |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
/** |
|
177
|
|
|
* {@inheritdoc} |
|
178
|
|
|
*/ |
|
179
|
2481 |
|
public function addBlockRenderer($blockClass, BlockRendererInterface $blockRenderer, int $priority = 0): ConfigurableEnvironmentInterface |
|
180
|
|
|
{ |
|
181
|
2481 |
|
$this->assertUninitialized('Failed to add block renderer.'); |
|
182
|
|
|
|
|
183
|
2478 |
|
if (!isset($this->blockRenderersByClass[$blockClass])) { |
|
184
|
2478 |
|
$this->blockRenderersByClass[$blockClass] = new PrioritizedList(); |
|
185
|
|
|
} |
|
186
|
|
|
|
|
187
|
2478 |
|
$this->blockRenderersByClass[$blockClass]->add($blockRenderer, $priority); |
|
188
|
2478 |
|
$this->injectEnvironmentAndConfigurationIfNeeded($blockRenderer); |
|
189
|
|
|
|
|
190
|
2478 |
|
return $this; |
|
191
|
|
|
} |
|
192
|
|
|
|
|
193
|
|
|
/** |
|
194
|
|
|
* {@inheritdoc} |
|
195
|
|
|
*/ |
|
196
|
2481 |
|
public function addInlineRenderer(string $inlineClass, InlineRendererInterface $renderer, int $priority = 0): ConfigurableEnvironmentInterface |
|
197
|
|
|
{ |
|
198
|
2481 |
|
$this->assertUninitialized('Failed to add inline renderer.'); |
|
199
|
|
|
|
|
200
|
2478 |
|
if (!isset($this->inlineRenderersByClass[$inlineClass])) { |
|
201
|
2478 |
|
$this->inlineRenderersByClass[$inlineClass] = new PrioritizedList(); |
|
202
|
|
|
} |
|
203
|
|
|
|
|
204
|
2478 |
|
$this->inlineRenderersByClass[$inlineClass]->add($renderer, $priority); |
|
205
|
2478 |
|
$this->injectEnvironmentAndConfigurationIfNeeded($renderer); |
|
206
|
|
|
|
|
207
|
2478 |
|
return $this; |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
/** |
|
211
|
|
|
* {@inheritdoc} |
|
212
|
|
|
*/ |
|
213
|
2493 |
|
public function getBlockParsers(): iterable |
|
214
|
|
|
{ |
|
215
|
2493 |
|
if (!$this->extensionsInitialized) { |
|
216
|
36 |
|
$this->initializeExtensions(); |
|
217
|
|
|
} |
|
218
|
|
|
|
|
219
|
2493 |
|
return $this->blockParsers->getIterator(); |
|
220
|
|
|
} |
|
221
|
|
|
|
|
222
|
|
|
/** |
|
223
|
|
|
* {@inheritdoc} |
|
224
|
|
|
*/ |
|
225
|
2418 |
|
public function getInlineParsersForCharacter(string $character): iterable |
|
226
|
|
|
{ |
|
227
|
2418 |
|
if (!$this->extensionsInitialized) { |
|
228
|
18 |
|
$this->initializeExtensions(); |
|
229
|
|
|
} |
|
230
|
|
|
|
|
231
|
2418 |
|
if (!isset($this->inlineParsersByCharacter[$character])) { |
|
232
|
2244 |
|
return []; |
|
233
|
|
|
} |
|
234
|
|
|
|
|
235
|
1368 |
|
return $this->inlineParsersByCharacter[$character]->getIterator(); |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
/** |
|
239
|
|
|
* {@inheritdoc} |
|
240
|
|
|
*/ |
|
241
|
2421 |
|
public function getDelimiterProcessors(): DelimiterProcessorCollection |
|
242
|
|
|
{ |
|
243
|
2421 |
|
if (!$this->extensionsInitialized) { |
|
244
|
6 |
|
$this->initializeExtensions(); |
|
245
|
|
|
} |
|
246
|
|
|
|
|
247
|
2421 |
|
return $this->delimiterProcessors; |
|
248
|
|
|
} |
|
249
|
|
|
|
|
250
|
|
|
/** |
|
251
|
|
|
* {@inheritdoc} |
|
252
|
|
|
*/ |
|
253
|
2463 |
|
public function getBlockRenderersForClass(string $blockClass): iterable |
|
254
|
|
|
{ |
|
255
|
2463 |
|
if (!$this->extensionsInitialized) { |
|
256
|
15 |
|
$this->initializeExtensions(); |
|
257
|
|
|
} |
|
258
|
|
|
|
|
259
|
2463 |
|
return $this->getRenderersByClass($this->blockRenderersByClass, $blockClass); |
|
260
|
|
|
} |
|
261
|
|
|
|
|
262
|
|
|
/** |
|
263
|
|
|
* {@inheritdoc} |
|
264
|
|
|
*/ |
|
265
|
2175 |
|
public function getInlineRenderersForClass(string $inlineClass): iterable |
|
266
|
|
|
{ |
|
267
|
2175 |
|
if (!$this->extensionsInitialized) { |
|
268
|
18 |
|
$this->initializeExtensions(); |
|
269
|
|
|
} |
|
270
|
|
|
|
|
271
|
2175 |
|
return $this->getRenderersByClass($this->inlineRenderersByClass, $inlineClass); |
|
272
|
|
|
} |
|
273
|
|
|
|
|
274
|
|
|
/** |
|
275
|
|
|
* Get all registered extensions |
|
276
|
|
|
* |
|
277
|
|
|
* @return ExtensionInterface[] |
|
278
|
|
|
*/ |
|
279
|
12 |
|
public function getExtensions(): iterable |
|
280
|
|
|
{ |
|
281
|
12 |
|
return $this->extensions; |
|
282
|
|
|
} |
|
283
|
|
|
|
|
284
|
|
|
/** |
|
285
|
|
|
* Add a single extension |
|
286
|
|
|
* |
|
287
|
|
|
* @param ExtensionInterface $extension |
|
288
|
|
|
* |
|
289
|
|
|
* @return $this |
|
290
|
|
|
*/ |
|
291
|
2481 |
|
public function addExtension(ExtensionInterface $extension): ConfigurableEnvironmentInterface |
|
292
|
|
|
{ |
|
293
|
2481 |
|
$this->assertUninitialized('Failed to add extension.'); |
|
294
|
|
|
|
|
295
|
2478 |
|
$this->extensions[] = $extension; |
|
296
|
2478 |
|
$this->uninitializedExtensions[] = $extension; |
|
297
|
|
|
|
|
298
|
2478 |
|
return $this; |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
2559 |
|
private function initializeExtensions() |
|
302
|
|
|
{ |
|
303
|
|
|
// Ask all extensions to register their components |
|
304
|
2559 |
|
while (!empty($this->uninitializedExtensions)) { |
|
305
|
2466 |
|
foreach ($this->uninitializedExtensions as $i => $extension) { |
|
306
|
2466 |
|
$extension->register($this); |
|
307
|
2466 |
|
unset($this->uninitializedExtensions[$i]); |
|
308
|
|
|
} |
|
309
|
|
|
} |
|
310
|
|
|
|
|
311
|
2559 |
|
$this->extensionsInitialized = true; |
|
312
|
|
|
|
|
313
|
|
|
// Lastly, let's build a regex which matches non-inline characters |
|
314
|
|
|
// This will enable a huge performance boost with inline parsing |
|
315
|
2559 |
|
$this->buildInlineParserCharacterRegex(); |
|
316
|
2559 |
|
} |
|
317
|
|
|
|
|
318
|
2529 |
|
private function injectEnvironmentAndConfigurationIfNeeded($object) |
|
319
|
|
|
{ |
|
320
|
2529 |
|
if ($object instanceof EnvironmentAwareInterface) { |
|
321
|
2481 |
|
$object->setEnvironment($this); |
|
322
|
|
|
} |
|
323
|
|
|
|
|
324
|
2529 |
|
if ($object instanceof ConfigurationAwareInterface) { |
|
325
|
2481 |
|
$object->setConfiguration($this->config); |
|
326
|
|
|
} |
|
327
|
2529 |
|
} |
|
328
|
|
|
|
|
329
|
2469 |
|
public static function createCommonMarkEnvironment(): ConfigurableEnvironmentInterface |
|
330
|
|
|
{ |
|
331
|
2469 |
|
$environment = new static(); |
|
332
|
2469 |
|
$environment->addExtension(new CommonMarkCoreExtension()); |
|
333
|
2469 |
|
$environment->mergeConfig([ |
|
334
|
1646 |
|
'renderer' => [ |
|
335
|
823 |
|
'block_separator' => "\n", |
|
336
|
|
|
'inner_separator' => "\n", |
|
337
|
|
|
'soft_break' => "\n", |
|
338
|
|
|
], |
|
339
|
2469 |
|
'html_input' => self::HTML_INPUT_ALLOW, |
|
340
|
|
|
'allow_unsafe_links' => true, |
|
341
|
|
|
'max_nesting_level' => \INF, |
|
342
|
|
|
]); |
|
343
|
|
|
|
|
344
|
2469 |
|
return $environment; |
|
345
|
|
|
} |
|
346
|
|
|
|
|
347
|
72 |
|
public static function createGFMEnvironment(): ConfigurableEnvironmentInterface |
|
348
|
|
|
{ |
|
349
|
72 |
|
$environment = self::createCommonMarkEnvironment(); |
|
350
|
72 |
|
$environment->addExtension(new GithubFlavoredMarkdownExtension()); |
|
351
|
|
|
|
|
352
|
72 |
|
return $environment; |
|
353
|
|
|
} |
|
354
|
|
|
|
|
355
|
|
|
/** |
|
356
|
|
|
* {@inheritdoc} |
|
357
|
|
|
*/ |
|
358
|
2229 |
|
public function getInlineParserCharacterRegex(): string |
|
359
|
|
|
{ |
|
360
|
2229 |
|
return $this->inlineParserCharacterRegex; |
|
361
|
|
|
} |
|
362
|
|
|
|
|
363
|
|
|
/** |
|
364
|
|
|
* {@inheritdoc} |
|
365
|
|
|
*/ |
|
366
|
222 |
|
public function addEventListener(string $eventClass, callable $listener, int $priority = 0): ConfigurableEnvironmentInterface |
|
367
|
|
|
{ |
|
368
|
222 |
|
$this->assertUninitialized('Failed to add event listener.'); |
|
369
|
|
|
|
|
370
|
222 |
|
if (!isset($this->listeners[$eventClass])) { |
|
371
|
222 |
|
$this->listeners[$eventClass] = new PrioritizedList(); |
|
372
|
|
|
} |
|
373
|
|
|
|
|
374
|
222 |
|
$this->listeners[$eventClass]->add($listener, $priority); |
|
375
|
|
|
|
|
376
|
222 |
|
if (\is_object($listener)) { |
|
377
|
222 |
|
$this->injectEnvironmentAndConfigurationIfNeeded($listener); |
|
378
|
|
|
} |
|
379
|
|
|
|
|
380
|
222 |
|
return $this; |
|
381
|
|
|
} |
|
382
|
|
|
|
|
383
|
|
|
/** |
|
384
|
|
|
* {@inheritdoc} |
|
385
|
|
|
*/ |
|
386
|
2466 |
|
public function dispatch(AbstractEvent $event): void |
|
387
|
|
|
{ |
|
388
|
2466 |
|
if (!$this->extensionsInitialized) { |
|
389
|
2466 |
|
$this->initializeExtensions(); |
|
390
|
|
|
} |
|
391
|
|
|
|
|
392
|
2466 |
|
$type = \get_class($event); |
|
393
|
|
|
|
|
394
|
2466 |
|
foreach ($this->listeners[$type] ?? [] as $listener) { |
|
395
|
219 |
|
if ($event->isPropagationStopped()) { |
|
396
|
3 |
|
return; |
|
397
|
|
|
} |
|
398
|
|
|
|
|
399
|
219 |
|
$listener($event); |
|
400
|
|
|
} |
|
401
|
2463 |
|
} |
|
402
|
|
|
|
|
403
|
2559 |
|
private function buildInlineParserCharacterRegex() |
|
404
|
|
|
{ |
|
405
|
2559 |
|
$chars = \array_unique(\array_merge( |
|
406
|
2559 |
|
\array_keys($this->inlineParsersByCharacter), |
|
407
|
2559 |
|
$this->delimiterProcessors->getDelimiterCharacters() |
|
408
|
|
|
)); |
|
409
|
|
|
|
|
410
|
2559 |
|
if (empty($chars)) { |
|
411
|
|
|
// If no special inline characters exist then parse the whole line |
|
412
|
81 |
|
$this->inlineParserCharacterRegex = '/^.+$/u'; |
|
413
|
|
|
} else { |
|
414
|
|
|
// Match any character which inline parsers are not interested in |
|
415
|
2478 |
|
$this->inlineParserCharacterRegex = '/^[^' . \preg_quote(\implode('', $chars), '/') . ']+/u'; |
|
416
|
|
|
} |
|
417
|
2559 |
|
} |
|
418
|
|
|
|
|
419
|
|
|
/** |
|
420
|
|
|
* @param string $message |
|
421
|
|
|
* |
|
422
|
|
|
* @throws \RuntimeException |
|
423
|
|
|
*/ |
|
424
|
2571 |
|
private function assertUninitialized(string $message) |
|
425
|
|
|
{ |
|
426
|
2571 |
|
if ($this->extensionsInitialized) { |
|
427
|
24 |
|
throw new \RuntimeException($message . ' Extensions have already been initialized.'); |
|
428
|
|
|
} |
|
429
|
2547 |
|
} |
|
430
|
|
|
|
|
431
|
|
|
/** |
|
432
|
|
|
* @param array<string, PrioritizedList> $list |
|
433
|
|
|
* @param string $class |
|
434
|
|
|
* |
|
435
|
|
|
* @return iterable |
|
436
|
|
|
*/ |
|
437
|
2481 |
|
private function getRenderersByClass(array &$list, string $class): iterable |
|
438
|
|
|
{ |
|
439
|
|
|
// If renderers are defined for this specific class, return them immediately |
|
440
|
2481 |
|
if (isset($list[$class])) { |
|
441
|
2466 |
|
return $list[$class]; |
|
442
|
|
|
} |
|
443
|
|
|
|
|
444
|
21 |
|
while ($parent = \get_parent_class($parent ?? $class)) { |
|
445
|
12 |
|
if (!isset($list[$parent])) { |
|
446
|
12 |
|
continue; |
|
447
|
|
|
} |
|
448
|
|
|
|
|
449
|
|
|
// "Cache" this result to avoid future loops |
|
450
|
6 |
|
return $list[$class] = $list[$parent]; |
|
451
|
|
|
} |
|
452
|
|
|
|
|
453
|
15 |
|
return []; |
|
|
|
|
|
|
454
|
|
|
} |
|
455
|
|
|
} |
|
456
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.