These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Robo\Collection; |
||
3 | |||
4 | use Consolidation\Config\Inject\ConfigForSetters; |
||
5 | use Robo\Config\Config; |
||
6 | use Psr\Log\LogLevel; |
||
7 | use Robo\Contract\InflectionInterface; |
||
8 | use Robo\Contract\TaskInterface; |
||
9 | use Robo\Contract\CompletionInterface; |
||
10 | use Robo\Contract\WrappedTaskInterface; |
||
11 | use Robo\Task\Simulator; |
||
12 | use ReflectionClass; |
||
13 | use Robo\Task\BaseTask; |
||
14 | use Robo\Contract\BuilderAwareInterface; |
||
15 | use Robo\Contract\CommandInterface; |
||
16 | use Robo\Contract\VerbosityThresholdInterface; |
||
17 | use Robo\State\StateAwareInterface; |
||
18 | use Robo\State\StateAwareTrait; |
||
19 | use Robo\Result; |
||
20 | |||
21 | /** |
||
22 | * Creates a collection, and adds tasks to it. The collection builder |
||
23 | * offers a streamlined chained-initialization mechanism for easily |
||
24 | * creating task groups. Facilities for creating working and temporary |
||
25 | * directories are also provided. |
||
26 | * |
||
27 | * ``` php |
||
28 | * <?php |
||
29 | * $result = $this->collectionBuilder() |
||
30 | * ->taskFilesystemStack() |
||
31 | * ->mkdir('g') |
||
32 | * ->touch('g/g.txt') |
||
33 | * ->rollback( |
||
34 | * $this->taskDeleteDir('g') |
||
35 | * ) |
||
36 | * ->taskFilesystemStack() |
||
37 | * ->mkdir('g/h') |
||
38 | * ->touch('g/h/h.txt') |
||
39 | * ->taskFilesystemStack() |
||
40 | * ->mkdir('g/h/i/c') |
||
41 | * ->touch('g/h/i/i.txt') |
||
42 | * ->run() |
||
43 | * ?> |
||
44 | * |
||
45 | * In the example above, the `taskDeleteDir` will be called if |
||
46 | * ``` |
||
47 | */ |
||
48 | class CollectionBuilder extends BaseTask implements NestedCollectionInterface, WrappedTaskInterface, CommandInterface, StateAwareInterface |
||
49 | { |
||
50 | use StateAwareTrait; |
||
51 | |||
52 | /** |
||
53 | * @var \Robo\Tasks |
||
54 | */ |
||
55 | protected $commandFile; |
||
56 | |||
57 | /** |
||
58 | * @var CollectionInterface |
||
59 | */ |
||
60 | protected $collection; |
||
61 | |||
62 | /** |
||
63 | * @var TaskInterface |
||
64 | */ |
||
65 | protected $currentTask; |
||
66 | |||
67 | /** |
||
68 | * @var bool |
||
69 | */ |
||
70 | protected $simulated; |
||
71 | |||
72 | /** |
||
73 | * @param \Robo\Tasks $commandFile |
||
74 | */ |
||
75 | public function __construct($commandFile) |
||
76 | { |
||
77 | $this->commandFile = $commandFile; |
||
78 | $this->resetState(); |
||
79 | } |
||
80 | |||
81 | View Code Duplication | public static function create($container, $commandFile) |
|
82 | { |
||
83 | $builder = new self($commandFile); |
||
84 | |||
85 | $builder->setLogger($container->get('logger')); |
||
86 | $builder->setProgressIndicator($container->get('progressIndicator')); |
||
87 | $builder->setConfig($container->get('config')); |
||
88 | $builder->setOutputAdapter($container->get('outputAdapter')); |
||
89 | |||
90 | return $builder; |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * @param bool $simulated |
||
95 | * |
||
96 | * @return $this |
||
97 | */ |
||
98 | public function simulated($simulated = true) |
||
99 | { |
||
100 | $this->simulated = $simulated; |
||
101 | return $this; |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * @return bool |
||
106 | */ |
||
107 | public function isSimulated() |
||
108 | { |
||
109 | if (!isset($this->simulated)) { |
||
110 | $this->simulated = $this->getConfig()->get(Config::SIMULATE); |
||
111 | } |
||
112 | return $this->simulated; |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * Create a temporary directory to work in. When the collection |
||
117 | * completes or rolls back, the temporary directory will be deleted. |
||
118 | * Returns the path to the location where the directory will be |
||
119 | * created. |
||
120 | * |
||
121 | * @param string $prefix |
||
122 | * @param string $base |
||
123 | * @param bool $includeRandomPart |
||
124 | * |
||
125 | * @return string |
||
126 | */ |
||
127 | public function tmpDir($prefix = 'tmp', $base = '', $includeRandomPart = true) |
||
128 | { |
||
129 | // n.b. Any task that the builder is asked to create is |
||
130 | // automatically added to the builder's collection, and |
||
131 | // wrapped in the builder object. Therefore, the result |
||
132 | // of any call to `taskFoo()` from within the builder will |
||
133 | // always be `$this`. |
||
134 | return $this->taskTmpDir($prefix, $base, $includeRandomPart)->getPath(); |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * Create a working directory to hold results. A temporary directory |
||
139 | * is first created to hold the intermediate results. After the |
||
140 | * builder finishes, the work directory is moved into its final location; |
||
141 | * any results already in place will be moved out of the way and |
||
142 | * then deleted. |
||
143 | * |
||
144 | * @param string $finalDestination The path where the working directory |
||
145 | * will be moved once the task collection completes. |
||
146 | * |
||
147 | * @return string |
||
148 | */ |
||
149 | public function workDir($finalDestination) |
||
150 | { |
||
151 | // Creating the work dir task in this context adds it to our task collection. |
||
152 | return $this->taskWorkDir($finalDestination)->getPath(); |
||
153 | } |
||
154 | |||
155 | public function addTask(TaskInterface $task) |
||
156 | { |
||
157 | $this->getCollection()->add($task); |
||
158 | return $this; |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * Add arbitrary code to execute as a task. |
||
163 | * |
||
164 | * @see \Robo\Collection\CollectionInterface::addCode |
||
165 | * |
||
166 | * @param callable $code |
||
167 | * @param int|string $name |
||
168 | * @return $this |
||
169 | */ |
||
170 | public function addCode(callable $code, $name = \Robo\Collection\CollectionInterface::UNNAMEDTASK) |
||
171 | { |
||
172 | $this->getCollection()->addCode($code, $name); |
||
173 | return $this; |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * Add a list of tasks to our task collection. |
||
178 | * |
||
179 | * @param TaskInterface[] $tasks |
||
180 | * An array of tasks to run with rollback protection |
||
181 | * |
||
182 | * @return $this |
||
183 | */ |
||
184 | public function addTaskList(array $tasks) |
||
185 | { |
||
186 | $this->getCollection()->addTaskList($tasks); |
||
187 | return $this; |
||
188 | } |
||
189 | |||
190 | public function rollback(TaskInterface $task) |
||
191 | { |
||
192 | // Ensure that we have a collection if we are going to add |
||
193 | // a rollback function. |
||
194 | $this->getCollection()->rollback($task); |
||
195 | return $this; |
||
196 | } |
||
197 | |||
198 | public function rollbackCode(callable $rollbackCode) |
||
199 | { |
||
200 | $this->getCollection()->rollbackCode($rollbackCode); |
||
201 | return $this; |
||
202 | } |
||
203 | |||
204 | public function completion(TaskInterface $task) |
||
205 | { |
||
206 | $this->getCollection()->completion($task); |
||
207 | return $this; |
||
208 | } |
||
209 | |||
210 | public function completionCode(callable $completionCode) |
||
211 | { |
||
212 | $this->getCollection()->completionCode($completionCode); |
||
213 | return $this; |
||
214 | } |
||
215 | |||
216 | /** |
||
217 | * @param string $text |
||
218 | * @param array $context |
||
219 | * @param string $level |
||
220 | * |
||
221 | * @return $this |
||
222 | */ |
||
223 | public function progressMessage($text, $context = [], $level = LogLevel::NOTICE) |
||
224 | { |
||
225 | $this->getCollection()->progressMessage($text, $context, $level); |
||
226 | return $this; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * @param \Robo\Collection\NestedCollectionInterface $parentCollection |
||
231 | * |
||
232 | * @return $this |
||
233 | */ |
||
234 | public function setParentCollection(NestedCollectionInterface $parentCollection) |
||
235 | { |
||
236 | $this->getCollection()->setParentCollection($parentCollection); |
||
237 | return $this; |
||
238 | } |
||
239 | |||
240 | /** |
||
241 | * Called by the factory method of each task; adds the current |
||
242 | * task to the task builder. |
||
243 | * |
||
244 | * TODO: protected |
||
245 | * |
||
246 | * @param TaskInterface $task |
||
247 | * |
||
248 | * @return $this |
||
249 | */ |
||
250 | public function addTaskToCollection($task) |
||
251 | { |
||
252 | // Postpone creation of the collection until the second time |
||
253 | // we are called. At that time, $this->currentTask will already |
||
254 | // be populated. We call 'getCollection()' so that it will |
||
255 | // create the collection and add the current task to it. |
||
256 | // Note, however, that if our only tasks implements NestedCollectionInterface, |
||
257 | // then we should force this builder to use a collection. |
||
258 | if (!$this->collection && (isset($this->currentTask) || ($task instanceof NestedCollectionInterface))) { |
||
259 | $this->getCollection(); |
||
260 | } |
||
261 | $this->currentTask = $task; |
||
262 | if ($this->collection) { |
||
263 | $this->collection->add($task); |
||
264 | } |
||
265 | return $this; |
||
266 | } |
||
267 | |||
268 | public function getState() |
||
269 | { |
||
270 | $collection = $this->getCollection(); |
||
271 | return $collection->getState(); |
||
272 | } |
||
273 | |||
274 | public function storeState($key, $source = '') |
||
0 ignored issues
–
show
|
|||
275 | { |
||
276 | return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args()); |
||
277 | } |
||
278 | |||
279 | public function deferTaskConfiguration($functionName, $stateKey) |
||
0 ignored issues
–
show
|
|||
280 | { |
||
281 | return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args()); |
||
282 | } |
||
283 | |||
284 | public function defer($callback) |
||
0 ignored issues
–
show
|
|||
285 | { |
||
286 | return $this->callCollectionStateFuntion(__FUNCTION__, func_get_args()); |
||
287 | } |
||
288 | |||
289 | protected function callCollectionStateFuntion($functionName, $args) |
||
290 | { |
||
291 | $currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask; |
||
292 | |||
293 | array_unshift($args, $currentTask); |
||
294 | $collection = $this->getCollection(); |
||
295 | $fn = [$collection, $functionName]; |
||
296 | |||
297 | call_user_func_array($fn, $args); |
||
298 | return $this; |
||
299 | } |
||
300 | |||
301 | public function setVerbosityThreshold($verbosityThreshold) |
||
302 | { |
||
303 | $currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask; |
||
304 | if ($currentTask) { |
||
305 | $currentTask->setVerbosityThreshold($verbosityThreshold); |
||
306 | return $this; |
||
0 ignored issues
–
show
The return type of
return $this; (Robo\Collection\CollectionBuilder ) is incompatible with the return type of the parent method Robo\Task\BaseTask::setVerbosityThreshold of type Robo\Common\VerbosityThresholdTrait .
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: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
307 | } |
||
308 | parent::setVerbosityThreshold($verbosityThreshold); |
||
309 | return $this; |
||
0 ignored issues
–
show
The return type of
return $this; (Robo\Collection\CollectionBuilder ) is incompatible with the return type of the parent method Robo\Task\BaseTask::setVerbosityThreshold of type Robo\Common\VerbosityThresholdTrait .
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: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
310 | } |
||
311 | |||
312 | |||
313 | /** |
||
314 | * Return the current task for this collection builder. |
||
315 | * TODO: Not needed? |
||
316 | * |
||
317 | * @return \Robo\Contract\TaskInterface |
||
318 | */ |
||
319 | public function getCollectionBuilderCurrentTask() |
||
320 | { |
||
321 | return $this->currentTask; |
||
322 | } |
||
323 | |||
324 | /** |
||
325 | * Create a new builder with its own task collection |
||
326 | * |
||
327 | * @return CollectionBuilder |
||
328 | */ |
||
329 | public function newBuilder() |
||
330 | { |
||
331 | $collectionBuilder = new self($this->commandFile); |
||
332 | $collectionBuilder->inflect($this); |
||
333 | $collectionBuilder->simulated($this->isSimulated()); |
||
334 | $collectionBuilder->setVerbosityThreshold($this->verbosityThreshold()); |
||
335 | $collectionBuilder->setState($this->getState()); |
||
336 | |||
337 | return $collectionBuilder; |
||
338 | } |
||
339 | |||
340 | /** |
||
341 | * Calling the task builder with methods of the current |
||
342 | * task calls through to that method of the task. |
||
343 | * |
||
344 | * There is extra complexity in this function that could be |
||
345 | * simplified if we attached the 'LoadAllTasks' and custom tasks |
||
346 | * to the collection builder instead of the RoboFile. While that |
||
347 | * change would be a better design overall, it would require that |
||
348 | * the user do a lot more work to set up and use custom tasks. |
||
349 | * We therefore take on some additional complexity here in order |
||
350 | * to allow users to maintain their tasks in their RoboFile, which |
||
351 | * is much more convenient. |
||
352 | * |
||
353 | * Calls to $this->collectionBuilder()->taskFoo() cannot be made |
||
354 | * directly because all of the task methods are protected. These |
||
355 | * calls will therefore end up here. If the method name begins |
||
356 | * with 'task', then it is eligible to be used with the builder. |
||
357 | * |
||
358 | * When we call getBuiltTask, below, it will use the builder attached |
||
359 | * to the commandfile to build the task. However, this is not what we |
||
360 | * want: the task needs to be built from THIS collection builder, so that |
||
361 | * it will be affected by whatever state is active in this builder. |
||
362 | * To do this, we have two choices: 1) save and restore the builder |
||
363 | * in the commandfile, or 2) clone the commandfile and set this builder |
||
364 | * on the copy. 1) is vulnerable to failure in multithreaded environments |
||
365 | * (currently not supported), while 2) might cause confusion if there |
||
366 | * is shared state maintained in the commandfile, which is in the |
||
367 | * domain of the user. |
||
368 | * |
||
369 | * Note that even though we are setting up the commandFile to |
||
370 | * use this builder, getBuiltTask always creates a new builder |
||
371 | * (which is constructed using all of the settings from the |
||
372 | * commandFile's builder), and the new task is added to that. |
||
373 | * We therefore need to transfer the newly built task into this |
||
374 | * builder. The temporary builder is discarded. |
||
375 | * |
||
376 | * @param string $fn |
||
377 | * @param array $args |
||
378 | * |
||
379 | * @return $this|mixed |
||
380 | */ |
||
381 | public function __call($fn, $args) |
||
382 | { |
||
383 | if (preg_match('#^task[A-Z]#', $fn) && (method_exists($this->commandFile, 'getBuiltTask'))) { |
||
384 | $saveBuilder = $this->commandFile->getBuilder(); |
||
385 | $this->commandFile->setBuilder($this); |
||
386 | $temporaryBuilder = $this->commandFile->getBuiltTask($fn, $args); |
||
387 | $this->commandFile->setBuilder($saveBuilder); |
||
388 | if (!$temporaryBuilder) { |
||
389 | throw new \BadMethodCallException("No such method $fn: task does not exist in " . get_class($this->commandFile)); |
||
390 | } |
||
391 | $temporaryBuilder->getCollection()->transferTasks($this); |
||
392 | return $this; |
||
393 | } |
||
394 | if (!isset($this->currentTask)) { |
||
395 | throw new \BadMethodCallException("No such method $fn: current task undefined in collection builder."); |
||
396 | } |
||
397 | // If the method called is a method of the current task, |
||
398 | // then call through to the current task's setter method. |
||
399 | $result = call_user_func_array([$this->currentTask, $fn], $args); |
||
400 | |||
401 | // If something other than a setter method is called, then return its result. |
||
402 | $currentTask = ($this->currentTask instanceof WrappedTaskInterface) ? $this->currentTask->original() : $this->currentTask; |
||
403 | if (isset($result) && ($result !== $currentTask)) { |
||
404 | return $result; |
||
405 | } |
||
406 | |||
407 | return $this; |
||
408 | } |
||
409 | |||
410 | /** |
||
411 | * Construct the desired task and add it to this builder. |
||
412 | * |
||
413 | * @param string|object $name |
||
414 | * @param array $args |
||
415 | * |
||
416 | * @return \Robo\Collection\CollectionBuilder |
||
417 | */ |
||
418 | public function build($name, $args) |
||
419 | { |
||
420 | $reflection = new ReflectionClass($name); |
||
421 | $task = $reflection->newInstanceArgs($args); |
||
422 | if (!$task) { |
||
423 | throw new RuntimeException("Can not construct task $name"); |
||
424 | } |
||
425 | $task = $this->fixTask($task, $args); |
||
426 | $this->configureTask($name, $task); |
||
427 | return $this->addTaskToCollection($task); |
||
428 | } |
||
429 | |||
430 | /** |
||
431 | * @param InflectionInterface $task |
||
432 | * @param array $args |
||
433 | * |
||
434 | * @return \Robo\Collection\CompletionWrapper|\Robo\Task\Simulator |
||
435 | */ |
||
436 | protected function fixTask($task, $args) |
||
437 | { |
||
438 | if ($task instanceof InflectionInterface) { |
||
439 | $task->inflect($this); |
||
440 | } |
||
441 | if ($task instanceof BuilderAwareInterface) { |
||
442 | $task->setBuilder($this); |
||
443 | } |
||
444 | if ($task instanceof VerbosityThresholdInterface) { |
||
445 | $task->setVerbosityThreshold($this->verbosityThreshold()); |
||
446 | } |
||
447 | |||
448 | // Do not wrap our wrappers. |
||
449 | if ($task instanceof CompletionWrapper || $task instanceof Simulator) { |
||
450 | return $task; |
||
451 | } |
||
452 | |||
453 | // Remember whether or not this is a task before |
||
454 | // it gets wrapped in any decorator. |
||
455 | $isTask = $task instanceof TaskInterface; |
||
456 | $isCollection = $task instanceof NestedCollectionInterface; |
||
457 | |||
458 | // If the task implements CompletionInterface, ensure |
||
459 | // that its 'complete' method is called when the application |
||
460 | // terminates -- but only if its 'run' method is called |
||
461 | // first. If the task is added to a collection, then the |
||
462 | // task will be unwrapped via its `original` method, and |
||
463 | // it will be re-wrapped with a new completion wrapper for |
||
464 | // its new collection. |
||
465 | if ($task instanceof CompletionInterface) { |
||
466 | $task = new CompletionWrapper(Temporary::getCollection(), $task); |
||
467 | } |
||
468 | |||
469 | // If we are in simulated mode, then wrap any task in |
||
470 | // a TaskSimulator. |
||
471 | if ($isTask && !$isCollection && ($this->isSimulated())) { |
||
472 | $task = new \Robo\Task\Simulator($task, $args); |
||
473 | $task->inflect($this); |
||
474 | } |
||
475 | |||
476 | return $task; |
||
477 | } |
||
478 | |||
479 | /** |
||
480 | * Check to see if there are any setter methods defined in configuration |
||
481 | * for this task. |
||
482 | */ |
||
483 | protected function configureTask($taskClass, $task) |
||
484 | { |
||
485 | $taskClass = static::configClassIdentifier($taskClass); |
||
486 | $configurationApplier = new ConfigForSetters($this->getConfig(), $taskClass, 'task.'); |
||
487 | $configurationApplier->apply($task, 'settings'); |
||
488 | |||
489 | // TODO: If we counted each instance of $taskClass that was called from |
||
490 | // this builder, then we could also apply configuration from |
||
491 | // "task.{$taskClass}[$N].settings" |
||
492 | |||
493 | // TODO: If the builder knew what the current command name was, |
||
494 | // then we could also search for task configuration under |
||
495 | // command-specific keys such as "command.{$commandname}.task.{$taskClass}.settings". |
||
496 | } |
||
497 | |||
498 | /** |
||
499 | * When we run the collection builder, run everything in the collection. |
||
500 | * |
||
501 | * @return \Robo\Result |
||
502 | */ |
||
503 | public function run() |
||
504 | { |
||
505 | $this->startTimer(); |
||
506 | $result = $this->runTasks(); |
||
507 | $this->stopTimer(); |
||
508 | $result['time'] = $this->getExecutionTime(); |
||
509 | $result->mergeData($this->getState()->getData()); |
||
510 | return $result; |
||
511 | } |
||
512 | |||
513 | /** |
||
514 | * If there is a single task, run it; if there is a collection, run |
||
515 | * all of its tasks. |
||
516 | * |
||
517 | * @return \Robo\Result |
||
518 | */ |
||
519 | protected function runTasks() |
||
520 | { |
||
521 | if (!$this->collection && $this->currentTask) { |
||
522 | $result = $this->currentTask->run(); |
||
523 | return Result::ensureResult($this->currentTask, $result); |
||
524 | } |
||
525 | return $this->getCollection()->run(); |
||
526 | } |
||
527 | |||
528 | /** |
||
529 | * @return string |
||
530 | */ |
||
531 | public function getCommand() |
||
532 | { |
||
533 | if (!$this->collection && $this->currentTask) { |
||
534 | $task = $this->currentTask; |
||
535 | $task = ($task instanceof WrappedTaskInterface) ? $task->original() : $task; |
||
536 | if ($task instanceof CommandInterface) { |
||
537 | return $task->getCommand(); |
||
538 | } |
||
539 | } |
||
540 | |||
541 | return $this->getCollection()->getCommand(); |
||
542 | } |
||
543 | |||
544 | /** |
||
545 | * @return \Robo\Collection\Collection |
||
546 | */ |
||
547 | public function original() |
||
548 | { |
||
549 | return $this->getCollection(); |
||
0 ignored issues
–
show
The return type of
return $this->getCollection(); (Robo\Collection\CollectionInterface ) is incompatible with the return type declared by the interface Robo\Contract\WrappedTaskInterface::original of type Robo\Contract\TaskInterface .
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: class Author {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
abstract class Post {
public function getAuthor() {
return 'Johannes';
}
}
class BlogPost extends Post {
public function getAuthor() {
return new Author('Johannes');
}
}
class ForumPost extends Post { /* ... */ }
function my_function(Post $post) {
echo strtoupper($post->getAuthor());
}
Our function
Loading history...
|
|||
550 | } |
||
551 | |||
552 | /** |
||
553 | * Return the collection of tasks associated with this builder. |
||
554 | * |
||
555 | * @return CollectionInterface |
||
556 | */ |
||
557 | public function getCollection() |
||
558 | { |
||
559 | if (!isset($this->collection)) { |
||
560 | $this->collection = new Collection(); |
||
561 | $this->collection->inflect($this); |
||
562 | $this->collection->setState($this->getState()); |
||
563 | $this->collection->setProgressBarAutoDisplayInterval($this->getConfig()->get(Config::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL)); |
||
564 | |||
565 | if (isset($this->currentTask)) { |
||
566 | $this->collection->add($this->currentTask); |
||
567 | } |
||
568 | } |
||
569 | return $this->collection; |
||
570 | } |
||
571 | } |
||
572 |
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.