Completed
Push — 3.8.x ( 235a90...008f6f )
by Tim
05:32
created

RoboFile::runTestsUnit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
/**
4
 * RoboFile.php
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2016 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/techdivision/import-cli-simple
18
 * @link      http://www.techdivision.com
19
 */
20
21
use Lurker\Event\FilesystemEvent;
22
use Symfony\Component\Finder\Finder;
23
24
/**
25
 * Defines the available build tasks.
26
 *
27
 * @author    Tim Wagner <[email protected]>
28
 * @copyright 2016 TechDivision GmbH <[email protected]>
29
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
30
 * @link      https://github.com/techdivision/import-cli-simple
31
 * @link      http://www.techdivision.com
32
 */
33
class RoboFile extends \Robo\Tasks
34
{
35
36
    /**
37
     * The build properties.
38
     *
39
     * @var array
40
     */
41
    protected $properties = array(
42
        'base.dir' => __DIR__,
43
        'etc.dir' => __DIR__ . '/etc',
44
        'dist.dir' => __DIR__ . '/dist',
45
        'vendor.dir' => __DIR__ . '/vendor',
46
        'target.dir' => __DIR__ . '/target',
47
        'symfony.dir' => __DIR__ . '/symfony',
48
        'webapp.name' => 'import-cli-simple',
49
        'webapp.version' => '3.8.12'
50
    );
51
52
    /**
53
     * Run's the composer install command.
54
     *
55
     * @return \Robo\Result The result
56
     */
57
    public function composerInstall()
58
    {
59
        // optimize autoloader with custom path
60
        return $this->taskComposerInstall()
0 ignored issues
show
Bug introduced by
The method preferDist does only exist in Robo\Task\Composer\Install, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
61
             ->preferDist()
62
             ->optimizeAutoloader()
63
             ->run();
64
    }
65
66
    /**
67
     * Run's the composer update command.
68
     *
69
     * @return \Robo\Result The result
70
     */
71
    public function composerUpdate()
72
    {
73
        // optimize autoloader with custom path
74
        return $this->taskComposerUpdate()
0 ignored issues
show
Bug introduced by
The method preferDist does only exist in Robo\Task\Composer\Update, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
75
             ->preferDist()
76
             ->optimizeAutoloader()
77
             ->run();
78
    }
79
80
    /**
81
     * Clean up the environment for a new build.
82
     *
83
     * @return \Robo\Result The result
84
     */
85
    public function clean()
86
    {
87
        return $this->taskDeleteDir($this->properties['target.dir'])->run();
88
    }
89
90
    /**
91
     * Prepare's the environment for a new build.
92
     *
93
     * @return \Robo\Result The result
94
     */
95
    public function prepare()
96
    {
97
98
        // prepare the directories
99
        return $this->taskFileSystemStack()
0 ignored issues
show
Bug introduced by
The method mkdir does only exist in Robo\Task\Filesystem\FilesystemStack, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
100
             ->mkdir($this->properties['dist.dir'])
101
             ->mkdir($this->properties['target.dir'])
102
             ->mkdir(sprintf('%s/reports', $this->properties['target.dir']))
103
             ->run();
104
    }
105
106
    /**
107
     * Prepare's the Docker environment for a new build.
108
     *
109
     * @param string $domainName    The domain name used to invoke the Magento 2 instance inside the Docker container
110
     * @param string $containerName The Docker container name
111
     *
112
     * @return void
113
     */
114
    public function prepareDocker($domainName, $containerName)
115
    {
116
117
        // stop the build on first failure of a task
118
        $this->stopOnFail(true);
119
120
        // prepare the filesystem
121
        $this->prepare();
122
123
        // initialize the variables to query whether or not the docker container has been started successfully
124
        $counter = 0;
125
        $magentoNotAvailable = true;
126
127
        do {
128
            // reset the result of the CURL request
129
            $res = null;
130
131
            // query whether or not the image already has been loaded
132
            exec(
133
                str_replace(
134
                    array('{domain-name}'),
135
                    array($domainName),
136
                    'curl --resolve {domain-name}:80:127.0.0.1 http://{domain-name}/magento_version'
137
                ),
138
                $res
139
            );
140
141
            // query whether or not the Docker has been started
142
            foreach ($res as $val) {
0 ignored issues
show
Bug introduced by
The expression $res of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
143
                if (strstr($val, 'Magento/')) {
144
                    $magentoNotAvailable = false;
145
                }
146
            }
147
148
            // raise the counter
149
            $counter++;
150
151
            // sleep while the docker container is not available
152
            if ($magentoNotAvailable === true) {
153
                sleep(1);
154
            }
155
156
        } while ($magentoNotAvailable && $counter < 30);
157
158
        // activate batch commit behaviour to improve performance
159
        $this->taskDockerExec($containerName)
0 ignored issues
show
Bug introduced by
The method interactive does only exist in Robo\Task\Docker\Exec, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
160
            ->interactive()
161
            ->exec('mysql -uroot -proot -e \'SET GLOBAL innodb_flush_log_at_trx_commit = 2\'')
162
            ->run();
163
164
        // grant the privilieges to connection from outsite the container
165
        $this->taskDockerExec($containerName)
166
            ->interactive()
167
            ->exec('mysql -uroot -proot -e \'GRANT ALL ON *.* TO "magento"@"%" IDENTIFIED BY "magento"\'')
168
            ->run();
169
170
        // flush the privileges
171
        $this->taskDockerExec($containerName)
172
            ->interactive()
173
            ->exec('mysql -uroot -proot -e "FLUSH PRIVILEGES"')
174
            ->run();
175
    }
176
177
    /**
178
     * Creates the a PHAR archive from the sources.
179
     *
180
     * @return void
181
     */
182
    public function createPhar()
183
    {
184
185
        // stop the build on first failure of a task
186
        $this->stopOnFail(true);
187
188
        // run the build process
189
        $this->build();
190
191
        // prepare the PHAR archive name
192
        $archiveName = sprintf(
193
            '%s/%s.phar',
194
            $this->properties['target.dir'],
195
            $this->properties['webapp.name']
196
        );
197
198
        // prepare the target directory
199
        $targetDir = $this->properties['target.dir'] . DIRECTORY_SEPARATOR . $this->properties['webapp.version'];
200
201
        // copy the composer.json file
202
        $this->taskFilesystemStack()
0 ignored issues
show
Bug introduced by
The method copy does only exist in Robo\Task\Filesystem\FilesystemStack, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
203
             ->copy(
204
                  __DIR__ . DIRECTORY_SEPARATOR . 'composer.json',
205
                  $targetDir. DIRECTORY_SEPARATOR. 'composer.json'
206
             )->run();
207
208
          // copy the .semver file
209
          $this->taskFilesystemStack()
210
               ->copy(
211
                   __DIR__ . DIRECTORY_SEPARATOR . '.semver',
212
                   $targetDir. DIRECTORY_SEPARATOR. '.semver'
213
               )->run();
214
215
          // copy the bootstrap.php file
216
          $this->taskFilesystemStack()
217
               ->copy(
218
                  __DIR__ . DIRECTORY_SEPARATOR . 'bootstrap.php',
219
                  $targetDir. DIRECTORY_SEPARATOR. 'bootstrap.php'
220
               )->run();
221
222
        // install the composer dependencies
223
        $this->taskComposerInstall()
0 ignored issues
show
Bug introduced by
The method dir does only exist in Robo\Task\Composer\Install, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
224
            ->dir($targetDir)
225
            ->noDev()
226
            ->optimizeAutoloader()
227
            ->run();
228
229
        // prepare the task
230
        $pharTask = $this->taskPackPhar($archiveName)
0 ignored issues
show
Bug introduced by
The method compress does only exist in Robo\Task\Development\PackPhar, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
231
            ->compress()
232
            ->stub('stub.php');
233
234
        // load a list with all the source files from the vendor directory
235
        $finder = Finder::create()->files()
236
            ->name('*.php')
237
            ->name('*.json')
238
            ->name('.semver')
239
            ->name('services.xml')
240
            ->name('services-1.0.xsd')
241
            ->in($targetDir)
242
            ->ignoreDotFiles(false);
243
244
        // iterate over the source files of the vendor directory and add them to the PHAR archive
245
        foreach ($finder as $file) {
246
            $pharTask->addFile($file->getRelativePathname(), $file->getRealPath());
247
        }
248
249
        // create the PHAR archive
250
        $pharTask->run();
251
252
        // verify PHAR archive is packed correctly
253
        $this->_exec(sprintf('php %s', $archiveName));
254
255
        // prepare the PHAR archive distribution name
256
        $distArchiveName = sprintf('%s/%s.phar', $this->properties['dist.dir'], $this->properties['webapp.name']);
257
258
        // clean up the dist directory
259
        $this->taskCleanDir($this->properties['dist.dir'])->run();
260
261
        // copy the latest PHAR archive to the dist directory
262
        $this->taskFilesystemStack()->copy($archiveName, $distArchiveName)->run();
263
    }
264
265
    /**
266
     * Load the repository source directories that matches the passed pattern.
267
     *
268
     * @param string $glue    The glue used the the directory are concatenated to a string
269
     * @param string $pattern The pattern used to load the source directories
270
     *
271
     * @return string The concatenated relative source directories
272
     */
273
    protected function loadLibrarySourceDirs(string $glue = ',', string $pattern = 'techdivision/*/src') : string
274
    {
275
276
        // load the source directories
277
        $sourceDirs = glob(sprintf('%s/%s', $this->properties['vendor.dir'], $pattern), GLOB_ONLYDIR);
278
279
        // cut-off the actual path
280
        array_walk($sourceDirs, function (&$value) {
281
            $value = ltrim(str_replace(__DIR__, '', $value), '/');
282
        });
283
284
        // implode and return the source directories
285
        return implode($glue, $sourceDirs);
286
    }
287
288
    /**
289
     * Run's the PHPMD.
290
     *
291
     * @return \Robo\Result The result
292
     */
293
    public function runMd()
294
    {
295
296
        // run the mess detector
297
        return $this->_exec(
298
            sprintf(
299
                '%s/bin/phpmd %s xml phpmd.xml --reportfile %s/reports/pmd.xml --ignore-violations-on-exit',
300
                $this->properties['vendor.dir'],
301
                $this->loadLibrarySourceDirs(),
302
                $this->properties['target.dir']
303
            )
304
        );
305
    }
306
307
    /**
308
     * Run's the PHPCodeSniffer.
309
     *
310
     * @return \Robo\Result The result
311
     */
312
    public function runCs()
313
    {
314
315
        // load the repositories that matches the pattern the vendor/techdivision/*/src directories
316
        $dirs = glob(sprintf('%s/techdivision/*/src', $this->properties['vendor.dir']), GLOB_ONLYDIR);
0 ignored issues
show
Unused Code introduced by
$dirs is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
317
318
        // run the code sniffer
319
        return $this->_exec(
320
            sprintf(
321
                '%s/bin/phpcs -n --report-full --extensions=php --standard=phpcs.xml --report-checkstyle=%s/reports/phpcs.xml %s',
322
                $this->properties['vendor.dir'],
323
                $this->properties['target.dir'],
324
                $this->loadLibrarySourceDirs(' ')
325
            )
326
        );
327
    }
328
329
    /**
330
     * Run's the PHPCPD.
331
     *
332
     * @return \Robo\Result The result
333
     */
334
    public function runCpd()
335
    {
336
337
        // prepare the patterns for the files that has to be ignored
338
        $ignore = array(
339
            'Utils/MemberNames',
340
            'Subjects/ConverterSubject',
341
            'Observers/CustomerAddressAttributeObserver',
342
            'Subjects/EeBunchSubject',
343
            'Subjects/BunchSubject',
344
            'Services/CategoryBunchProcessor',
345
            'Plugins/MissingOptionValuesPlugin',
346
            'Observers/ProductToAttributeOptionValueConverterObserver'
347
        );
348
349
        // run the copy past detector
350
        return $this->_exec(
351
            sprintf(
352
                '%s/bin/phpcpd --regexps-exclude %s %s/techdivision/*/src --log-pmd %s/reports/pmd-cpd.xml',
353
                $this->properties['vendor.dir'],
354
                implode(',', $ignore),
355
                $this->properties['vendor.dir'],
356
                $this->properties['target.dir']
357
            )
358
        );
359
    }
360
361
    /**
362
     * Run's the PHPUnit testsuite.
363
     *
364
     * @return \Robo\Result The result
365
     */
366
    public function runTestsUnit()
367
    {
368
369
        // run PHPUnit
370
        return $this->taskPHPUnit(
0 ignored issues
show
Bug introduced by
The method configFile does only exist in Robo\Task\Testing\PHPUnit, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
371
                sprintf(
372
                    '%s/bin/phpunit --testsuite "techdivision/import-cli-simple PHPUnit testsuite"',
373
                    $this->properties['vendor.dir']
374
                )
375
            )
376
            ->configFile('phpunit.xml')
377
            ->run();
378
    }
379
380
    /**
381
     * Run's the integration testsuite.
382
     *
383
     * This task uses the Magento 2 docker image generator from https://github.com/techdivision/magento2-docker-imgen. To execute
384
     * this task, it is necessary that you've setup a running container with the domain name, passed as argument.
385
     *
386
     * @return \Robo\Result The result
387
     */
388
    public function runTestsIntegration()
389
    {
390
391
        // run the integration testsuite
392
        return $this->taskPHPUnit(
0 ignored issues
show
Bug introduced by
The method configFile does only exist in Robo\Task\Testing\PHPUnit, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
393
                sprintf(
394
                    '%s/bin/phpunit --testsuite "techdivision/import-cli-simple PHPUnit integration testsuite"',
395
                    $this->properties['vendor.dir']
396
                )
397
             )
398
             ->configFile('phpunit.xml')
399
             ->run();
400
    }
401
402
    /**
403
     * Run's the acceptance testsuite.
404
     *
405
     * This task uses the Magento 2 docker image generator from https://github.com/techdivision/magento2-docker-imgen. To execute
406
     * this task, it is necessary that you've setup a running container with the domain name, passed as argument.
407
     *
408
     * @return \Robo\Result The result
409
     */
410
    public function runTestsAcceptance($magentoEdition = 'ce', $magentoVersion = '2.3.3')
411
    {
412
413
        // initialize the default tags
414
        $tags = sprintf('@%s&&@%s&&~@customer&&~@customer-address', strtolower($magentoEdition), implode('.', sscanf($magentoVersion, "%d.%d")));
415
416
        // query whether or not the version is lower than 2.3.3, because then we've to ignore the MSI tests
417
        if (version_compare($magentoVersion, '2.3.2') < 1) {
418
            $tags = sprintf('%s&&~msi', $tags);
419
        }
420
421
        // finally, invoke the acceptance tests
422
        return $this->taskBehat()
0 ignored issues
show
Bug introduced by
The method format does only exist in Robo\Task\Testing\Behat, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
423
            ->format('pretty')
424
            ->option('tags', $tags)
425
            ->noInteraction()
426
            ->run();
427
        }
428
429
    /**
430
     * Raising the semver version number.
431
     *
432
     * @return \Robo\Result The result
433
     */
434
    public function semver()
435
    {
436
        return $this->taskSemVer('.semver')
0 ignored issues
show
Bug introduced by
The method prerelease does only exist in Robo\Task\Development\SemVer, but not in Robo\Collection\CollectionBuilder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
437
             ->prerelease('beta')
438
             ->run();
439
    }
440
441
    /**
442
     * The complete build process.
443
     *
444
     * @return void
445
     */
446
    public function build()
447
    {
448
449
        // stop the build on first failure of a task
450
        $this->stopOnFail(true);
451
452
        // process the build
453
        $this->clean();
454
        $this->prepare();
455
        $this->runCpd();
456
        $this->runCs();
457
        $this->runMd();
458
        $this->runTestsUnit();
459
    }
460
}
461