
Tools of the Trade Sebastian Bergmann Sebastian Bergmann Helps teams build testable soware and implement ecient tests. Interessengemeinscha PHP e.V. Als gemeinnütziger Verein möchten wir die Akzeptanz, Verbreitung und Weiterentwicklung der Programmiersprache PHP und das Wissen um die Programmiersprache PHP in Wissenscha, Forschung und Ausbildung ördern. https://igphp.de/ @igphp Code Editing PhpStorm is the only PHP IDE that deserves to be called IDE, IMO. Everything else is inferior at best and only gets in your way at worst. PhpStorm is the only PHP IDE that deserves to be called IDE, IMO. Everything else is inferior at best and only gets in your way at worst. I am not paid to say that. I simply cannot imagine working productively with something else. Php Inspections (EA Extended) Php Inspections (EA Ultimate) Dependency Management https://github.com/composer/getcomposer.org/issues/36 https://youtu.be/Ci_I0ATr748 Composer "[e]nables you to declare the libraries you depend on" and "[]inds out which versions of which packages can and need to be installed, and installs them (meaning it downloads them into your project)". $ curl -s https://getcomposer.org/installer | php $ php composer.phar --version $ chmod +x composer.phar $ mv composer.phar /usr/local/bin/composer $ composer self-update Do not "cURL and pipe to bash"! Users are encouraged by documentation to copy/paste commands such as $ curl -s https://getcomposer.org/installer | php into their shell. This prevents any verication of authenticity and integrity of the downloaded executable before running it. Users doing this are literally asking for their system to be compromised! https://thephp.cc/news/2019/02/blast-from-the-past Life is too short to talk about dead technology. $ mkdir project $ cd project $ composer require sebastian/diff Using version ^3.0 for sebastian/diff ./composer.json has been created Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 1 install, 0 updates, 0 removals - Installing sebastian/diff (3.0.0): Loading from cache Writing lock file Generating autoload files $ tree . ├── composer.json ├── composer.lock └── vendor ├── autoload.php ├── composer │ └── ... └── sebastian └── diff └── ... 15 directories, 62 files composer.json { "require": { "sebastian/diff": "^3.0" } } composer.json ⇨ Dependency Resolution ⇨ composer.lock composer.lock ⇨ Download ⇨ Installation ⇨ Autoloader Generation composer.lock not under version control composer.lock under version control composer.lock and vendor under version control PHA Installation and Verication Environment "PHIVE makes installation easy by providing a means to resolve [a] given alias to an actual download location, including the verication of the certicate supplied by the server. Once downloaded, the archive’s SHA1, SHA256 or SHA512 hash is veried as well as its OpenPGP/GnuPG or OpenSSL signature." $ wget -O phive.phar https://phar.io/releases/phive.phar $ wget -O phive.phar.asc https://phar.io/releases/phive.phar.asc $ gpg --keyserver hkps.pool.sks-keyservers.net --recv-keys 0x9D8A98B29B2D5D79 $ gpg --verify phive.phar.asc phive.phar $ php phive.phar --version $ chmod +x phive.phar $ mv phive.phar /usr/local/bin/phive $ phive self-update $ mkdir project $ cd project $ phive install phpunit Phive 0.12.4 - Copyright (C) 2015-2019 by Arne Blankerts, Sebastian Heuer and Contributors Linking /home/sb/.phive/phars/phpunit-8.3.5.phar to /home/sb/project/tools/phpunit $ tree . ├── phive.xml └── tools └── phpunit -> /home/sb/.phive/phars/phpunit-8.3.5.phar 1 directory, 2 files $ mkdir project $ cd project $ phive install --copy phpunit Phive 0.12.4 - Copyright (C) 2015-2019 by Arne Blankerts, Sebastian Heuer and Contributors Copying phpunit-8.3.5.phar to /home/sb/project/tools/phpunit $ tree . ├── phive.xml └── tools └── phpunit 1 directory, 2 files phive.xml <?xml version="1.0" encoding="UTF-8"?> <phive xmlns="https://phar.io/phive"> <phar name="phpunit" version="^8.3" installed="8.3.5" location="./tools/phpunit" copy="true"/> </phive> tools not under version control tools under version control So ... should you install tools using Composer or use PHARs? https://twitter.com/s_bergmann/status/999635212723212288 php-scoper https://github.com/sebastianbergmann/phpunit/issues/2015 Static Analysis $ wget https://github.com/vimeo/psalm/releases/download/3.5.1/psalm.phar $ chmod +x psalm.phar $ mv psalm.phar tools/psalm $ ./tools/psalm --version Psalm 3.5.1@deb36e8b273d4b25601f1991482a69d412e3169f $ phive install --copy psalm $ ./tools/psalm --version Psalm 3.5.1@deb36e8b273d4b25601f1991482a69d412e3169f <?php function foo(string $s): void { return 'bar'; } $a = ['hello', 5]; foo($a[1]); foo(); if (rand(0, 1)) $b = 5; echo $b; $c = rand(0, 5); if ($c) {} elseif ($c) {} ERROR: InvalidReturnStatement - 3:12 - No return values are expected for foo INFO: UnusedParam - 2:21 - Param $s is never referenced in this method ERROR: InvalidReturnType - 2:26 - The declared return type 'void' for foo is incorrect, got 'string' ERROR: InvalidScalarArgument - 7:5 - Argument 1 of foo expects string, int(5) provided ERROR: TooFewArguments - 8:1 - Too few arguments for method foo - expecting 1 but saw 0 INFO: PossiblyUndefinedGlobalVariable - 11:6 - Possibly undefined global variable $b, first seen on line 10 ERROR: TypeDoesNotContainType - 14:20 - Found a contradiction when evaluating $c and trying to reconcile type 'int(0)' to !falsy <?php declare(strict_types=1); namespace PHPUnit\Util\Annotation; final class DocBlock { // ... /** @var array<string, array<int, string>> */ private $symbolAnnotations; // ... } <?php declare(strict_types=1); namespace PHPUnit\Framework; abstract class TestCase extends Assert implements SelfDescribing, Test { // ... /** * @param string|string[] $originalClassName * * @psalm-template RealInstanceType of object * @psalm-param class-string<RealInstanceType>|string[] $originalClassName * @psalm-return MockObject&RealInstanceType */ protected function createMock($originalClassName): MockObject { return $this->getMockBuilder($originalClassName) ->disableOriginalConstructor() ->disableOriginalClone() ->disableArgumentCloning() ->disallowMockingUnknownTypes() ->getMock(); } // ... } <?php declare(strict_types=1); namespace PHPUnit\Util; final class Test { // ... public static function getMissingRequirements(string $className, string $methodName): array { // ... if (!empty($required['PHP'])) { $operator = empty($required['PHP']['operator']) ? '>=' : $required['PHP']['operator']; if (!\version_compare(\PHP_VERSION, $required['PHP']['version'], $operator)) { $missing[] = \sprintf('PHP %s %s is required.', $operator, $required['PHP']['version']); $hint = $hint ?? 'PHP'; } } elseif (!empty($required['PHP_constraint'])) { // ... } // ... } ERROR: InvalidArgument - src/Util/Test.php:303:78 - Argument 3 of version_compare expects string(\x3c)|string(lt)|string(\x3c=)|string(le)| string(\x3e)|string(gt)|string(\x3e=)|string(ge)|string(==)|string(=)|string(eq)| string(!=)|string(\x3c\x3e)|string(ne), string(>=)|mixed provided --- a/src/Util/Test.php +++ b/src/Util/Test.php @@ -300,6 +301,8 @@ public static function getMissingRequirements(string $className, string $met if (!empty($required['PHP'])) { $operator = empty($required['PHP']['operator']) ? '>=' : $required['PHP']['operator + self::ensureOperatorIsValid($operator); + if (!\version_compare(\PHP_VERSION, $required['PHP']['version'], $operator)) { $missing[] = \sprintf('PHP %s %s is required.', $operator, $required['PHP']['ve $hint = $hint ?? 'PHP'; @@ -1279,4 +1286,19 @@ private static function shouldCoversAnnotationBeUsed(array $annotations): return true; } + + private static function ensureOperatorIsValid(string $operator): void + { + if (!\in_array($operator, ['<', 'lt', '<=', 'le', '>', 'gt', '>=', 'ge', '==', '=', 'eq + throw new Exception( + \sprintf( + '"%s" is not a valid version_compare() operator', + $operator + ) + ); + } + } } <?php declare(strict_types=1); /** @psalm-pure */ function f(int $x): int { /** @var int $i */ static $i = 0; $i += $x; return $i; } ERROR: ImpureStaticVariable - src/test.php:6:5 - Cannot use a static variable in a mutation-free context <?php declare(strict_types=1); /** @psalm-pure */ function f(int $x): int { fopen(__FILE__, 'r'); return $x; } ERROR: ImpureFunctionCall - src/test.php:5:5 - Cannot call an impure function from a mutation-free context fopen(__FILE__, 'r'); Roave Backward Compatibility Check $ wget https://github.com/Roave/BackwardCompatibilityCheck/releases/download/4.1.0/roave-backward-compatibility-check.phar $ chmod +x roave-backward-compatibility-check $ mv roave-backward-compatibility-check tools/roave-backward-compatibility-check $ ./tools/roave-backward-compatibility-check --version roave/backward-compatibility-check 4.1.0@5092098994e3de84300a71c997494d6f637e839d $ ./tools/roave-backward-compatibility-check --from=7.5.16 --to=8.0.0 [BC] CHANGED: Class PHPUnit\Util\TestDox\XmlResultPrinter became final [BC] CHANGED: PHPUnit\Util\TestDox\XmlResultPrinter was marked "@internal" [BC] CHANGED: Class PHPUnit\Util\TestDox\TextResultPrinter became final [BC] CHANGED: PHPUnit\Util\TestDox\TextResultPrinter was marked "@internal" [BC] REMOVED: Class PHPUnit\Util\TestDox\TestResult has been deleted [BC] CHANGED: PHPUnit\Util\TestDox\ResultPrinter was marked "@internal" [BC] CHANGED: PHPUnit\Util\TestDox\NamePrettifier was marked "@internal" [BC] CHANGED: PHPUnit\Util\TestDox\HtmlResultPrinter was marked "@internal" [BC] CHANGED: The return type
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages105 Page
-
File Size-