Coding style,
Static code analysis and PHP
1
Outline
About me
What's Coding style?
PSR-2與PSR-12程式碼⾵格標準。
What's static code analysis?
PHPStan
Psalm
Phan
CI/CD examples
Laravel framework integration
2
About me
Peter
Active open source contributor
An associate engineer
DevOps
Back-end
System Architecture Researching
Web Application Security
PHP, Python and JavaScript
Smart Grid Technology (2017~2021)
Database, Data platform architecture (2021~)
GitHub
3
What's coding style?
AKA Programming style
4
PHP有Coding style嗎?
5
PHP有Coding style嗎?
Code Style Guide
6
Coding style
Founded by PHP-FIG
PHP Framework Interop Group
PSR-1
PSR-2
PSR-12
More standard docs
https://www.php-fig.org
https://github.com/php-fig
https://github.com/php-fig/fig-standards/tree/master/accepted
7
PSR-1 Overview
Files MUST use only <?php and <?= tags.
Files MUST use only UTF-8 without BOM for PHP code.
Files SHOULD either declare symbols (classes, functions, constants, etc.)
or cause side-effects (e.g. generate output, change .ini settings, etc.) but
SHOULD NOT do both.
Namespaces and classes MUST follow an "autoloading" PSR: [PSR-0, PSR-
4].
Class names MUST be declared in StudlyCaps.
Class constants MUST be declared in all upper case with underscore
separators.
Method names MUST be declared in camelCase.
 
8
PSR-2 Overview(Deprecated)
Code MUST follow a "coding style guide" PSR [ ].
Code MUST use 4 spaces for indenting, not tabs.
There MUST NOT be a hard limit on line length; the soft limit MUST be 120 characters; lines SHOULD be 80 characters or less.
There MUST be one blank line after the namespace declaration, and there MUST be one blank line after the block of use
declarations.
Opening braces for classes MUST go on the next line, and closing braces MUST go on the next line after the body.
Opening braces for methods MUST go on the next line, and closing braces MUST go on the next line after the body.
Visibility MUST be declared on all properties and methods; abstract and final MUST be declared before the visibility; static
MUST be declared after the visibility.
Control structure keywords MUST have one space after them; method and function calls MUST NOT.
Opening braces for control structures MUST go on the same line, and closing braces MUST go on the next line after the body.
Opening parentheses for control structures MUST NOT have a space after them, and closing parentheses for control
structures MUST NOT have a space before.
PSR-1
9
PSR-12
This specification extends, expands and replaces PSR-2, the
coding style guide and requires adherence to PSR-1, the basic
coding standard.
10
11
規則太多要檢查,有沒有檢查⼯具?
12
PHP_CodeSniffer
PHP-CS-Fixer
13
PHP_CodeSniffer
curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar
chmod +x phpcs.phar
mv phpcs.phar phpcs
phpcs --help
phpcs --standard=PSR2 src/ tests/
curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcbf.phar
chmod +x phpcbf.phar
mv phpcbf.phar phpcbf
phpcbf --help
phpcbf --standard=PSR2 src/ tests/
14
phpcs --standard=PSR2
FILE: ...n-source-contributions/localized/src/Validation/LtValidation.php
----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
31 | ERROR | [x] Use single instead of double quotes for simple
| | strings.
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------
FILE: ...is/build/open-source-contributions/localized/tests/bootstrap.php
----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
15 | ERROR | [x] Use single instead of double quotes for simple
| | strings.
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------
FILE: ...n-source-contributions/localized/src/Validation/BrValidation.php
----------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 1 LINE
----------------------------------------------------------------------
196 | ERROR | [x] Use single instead of double quotes for simple
| | strings.
196 | ERROR | [x] Use single instead of double quotes for simple
| | strings.
----------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
15
phpcs --standard=PSR2
16
phpcbf --standard=PSR2
17
phpcs.xml
<?xml version="1.0"?>
<ruleset name="Coding Standard">
<arg name="basepath" value="."/>
<arg name="colors"/>
<arg value="sp"/>
<config name="ignore_warnings_on_exit" value="1"/>
<file>./src</file>
<file>./tests</file>
<rule ref="PSR2"></rule>
<!-- <rule ref="PSR12"></rule> -->
<rule ref="Squiz.Commenting.ClassComment">
<exclude name="Squiz.Commenting.ClassComment.TagNotAllowed"/>
<type>warning</type>
<exclude-pattern>*/tests/</exclude-pattern>
</rule>
<rule ref="Squiz.Commenting.ClassComment.Missing">
<type>warning</type>
</rule>
<rule ref="Squiz.Commenting.FunctionComment.Missing">
<type>warning</type>
<exclude-pattern>*/config/</exclude-pattern>
/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
phpcs.xml.dist
18
PHP-CS-Fixer
curl -OL https://cs.symfony.com/download/php-cs-fixer-v2.phar
php php-cs-fixer-v2.phar fix --dry-run --format=txt --verbose --diff --diff-
format=udiff --config=.cs.php
curl -OL https://cs.symfony.com/download/php-cs-fixer-v3.phar
php php-cs-fixer-v3.phar fix --dry-run --format=txt --verbose --diff --diff-
format=udiff --config=.cs.php
19
.cs.php
<?php
return PhpCsFixerConfig::create()
->setUsingCache(false)
->setRiskyAllowed(true)
//->setCacheFile(__DIR__ . '/.php_cs.cache')
->setRules([
'@PSR1' => true,
'@PSR2' => true,
'@Symfony' => true,
'psr4' => true,
'yoda_style' => false,
'array_syntax' => ['syntax' => 'short'],
'list_syntax' => ['syntax' => 'short'],
'concat_space' => ['spacing' => 'one'],
'cast_spaces' => ['space' => 'none'],
'compact_nullable_typehint' => true,
'increment_style' => ['style' => 'post'],
'declare_equal_normalize' => ['space' => 'single'],
'no_short_echo_tag' => true,
'protected_to_private' => false,
'phpdoc_align' => false,
'phpdoc_add_missing_param_annotation' => ['only_untyped' => false],
'phpdoc_order' => true, // psr-5
'phpdoc_no_empty_return' => false,
'align multiline comment' => true, // psr-5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
PHP-CS-Fixer rules
20
PHP-CS-Fixer Rules
21
What's static code analysis?
22
Static Code Analysis
It's the analysis of computer software that is performed without actually
executing programs.
Dynamic code analysis is the analysis of computer software that is
performed by executing programs.
Unit tests, integration tests, system tests and acceptance tests use dynamic testing.
23
Static Code Analysis for PHP
Psalm
PHPStan
Phan→The PHP Father recommended
24
Installation
25
Installation
composer require phpstan/phpstan:0.* --dev
composer require vimeo/psalm:4.* --dev
composer require phan/phan:5.* --dev
26
Standard Checks
there are no syntax errors;
all the classes, methods, functions and constants exist;
the variables exist;
the hints in PHPDoc correspond to reality;
there are no arguments or variables unused.
Avoid copy-caste code errors and careless
27
Data type checks
Most analyzers allow to configure the level of strictness of checking and
imitate strict_types:
they check that String or Boolean aren’t passed to this function.
28
Union types
Most analyzers allow to configure the level of strictness of checking and
imitate strict_types:
they check that String or Boolean aren’t passed to this function.
/**
* @var string|int|bool $yes_or_no
*/
function isYes($yes_or_no) :bool
{
if (is_numeric($yes_or_no)) {
return $yes_or_no > 0;
} else {
return strtoupper($yes_or_no) == 'YES';
}
}
1
2
3
4
5
6
7
8
9
10
11
29
False type
Most analyzers allow to configure the level of strictness of checking and
imitate strict_types:
they check that String or Boolean aren’t passed to this function.
/** @return int|bool */
function fwrite(...) {
…
}
1
2
3
4
30
False type Error
<?php
/** @return resource|bool */
function open_file() {
$fp = fopen('./composer.json', 'r');
if($fp === false) {
return false;
}
return fwrite($fp, "some string");
}
1
2
3
4
5
6
7
8
9
10
11
lee@lee-VirtualBox:~/phpstan-example$ vendor/bin/phpstan analyse ./false_type.php --level=max -c phpstan
------ --------------------------------------------------------------------------------------------
Line false_type.php
------ --------------------------------------------------------------------------------------------
4 Function open_file() never returns resource so it can be removed from the return typehint.
10 Function open_file() should return bool|resource but returns int|false.
------ --------------------------------------------------------------------------------------------
1
2
3
4
5
6
7
31
False type Error Fix
<?php
/** @return int|false */
function open_file() {
$fp = fopen('./composer.json', 'r');
if($fp === false) {
return false;
}
return fwrite($fp, "some string");
}
1
2
3
4
5
6
7
8
9
10
11
lee@lee-VirtualBox:~/phpstan-example$ vendor/bin/phpstan analyse ./false_type.php 
--level=max -c phpstan.neon --no-progress --ansi
[OK] No errors
1
2
3
4
32
Array shapes
<?php
/** @return array */
function array_func(array $arr) {
return $arr;
}
1
2
3
4
5
6
lee@lee-VirtualBox:~/phpstan-example$ vendor/bin/phpstan analyse ./array_example.php 
--level=max -c phpstan.neon --no-progress --ansi
------ -----------------------------------------------------------------------------------------------
Line array_example.php
------ -----------------------------------------------------------------------------------------------
4 Function array_func() has parameter $arr with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
4 Function array_func() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
------ -----------------------------------------------------------------------------------------------
[ERROR] Found 2 errors
1
2
3
4
5
6
7
8
9
10
11
12
13
33
Array shapes fix
<?php
/**
@param array<string> $arr
@return array<string>
*/
function array_func($arr) {
return $arr;
}
1
2
3
4
5
6
7
8
9
34
Overview of static code analysis tools
35
PHPStan
Developed by
Install it (the simplest way is via Composer)
Configure it (optional)
Run it
Ondřej Mirtes
lee@lee-VirtualBox:~/phpstan-example$ vendor/bin/phpstan analyse ./array_example.php
1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
[OK] No errors
💡 Tip of the Day:
PHPStan is performing only the most basic checks.
You can pass a higher rule level through the --level option
(the default and current level is 0) to analyse code more thoroughly.
lee@lee-VirtualBox:~/phpstan-example$
1
2
3
4
5
6
7
8
9
10
11
12
13
14 36
PHPStan Key Features
PHPStan will try to autoload unknown classes.
If some classes are not autoloaded, it will not be able to find them and
will return an error.
If using magical methods via __call, __get, or __set, it can write a plug-in
for PHPStan.
In actual fact, PHPStan doesn’t only perform autoload in the case of
unknown classes, but it also does so for all classes.
Using for configuration.
 No support for its PHPDoc tags @phpstan-var, @phpstan-return etc.
PhpStan has a playground website .
neon-format
 https://phpstan.org
37
Phan
Developed by the Etsy company. First commits by Rasmus Lerdorf.
Requiring the php-ast extension.
Plugin example is available .
 Creating a  file.
Playground website is .
here
.phan/config.php
available
lee@lee-VirtualBox:~/phpstan-example$ php vendor/bin/phan array_example.php
analyze ████████████████████████████████████████████████████████████ 100.0% 29MB/29MB
lee@lee-VirtualBox:~/phpstan-example$ php vendor/bin/phan array_example.php
analyze ████████████████████████████████████████████████████████████ 100.0% 28MB/31MB
array_example.php:9 PhanSyntaxError syntax error, unexpected '}', expecting ';' (at column 1)
1
2
3
4
5
6
38
Psalm
Developed by the Vimeo company
Annotations code
XML format file about configuration
Type aliases
array
closure
union type (for example, several classes or a class and other types)
enum
39
psalm.xml
<?xml version="1.0"?>
<psalm
errorLevel="1"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
https://github.com/Innmind/XML/blob/develop/psalm.xml
40
vendor/bin/psalm
░░░░░░░E░░░░E░E░░░EE░░░░░░░░░░░E░░░░E░░░░░E░E░░
ERROR: ParamNameMismatch - src/Element/Element.php:131:54 - Argument 2 of InnmindXmlElementElement::
public function replaceChild(int $position, Node $node): Node
ERROR: ParamNameMismatch - src/Element/SelfClosingElement.php:36:54 - Argument 2 of InnmindXmlElement
public function replaceChild(int $position, Node $node): Node
ERROR: ParamNameMismatch - src/Node/CharacterData.php:43:54 - Argument 2 of InnmindXmlNodeCharacterD
public function replaceChild(int $position, Node $node): Node
ERROR: ParamNameMismatch - src/Node/Comment.php:43:54 - Argument 2 of InnmindXmlNodeComment::replace
public function replaceChild(int $position, Node $node): Node
ERROR: ParamNameMismatch - src/Node/Document.php:86:54 - Argument 2 of InnmindXmlNodeDocument::repla
public function replaceChild(int $position, Node $node): Node
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
https://github.com/Innmind/XML/issues/2
41
CI/CD examples
42
GitHub Workflow examples
1. Using Composer to install required development dependencies.
2. GithubAction for PHP-CS-Fixer.
3. PHP Static Analysis in Github Actions.
43
composer install
.......
psalm:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['7.4', '8.0']
name: 'Psalm'
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: mbstring, intl
- name: Get Composer Cache Directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Dependencies
run: composer install
- name: Psalm
run: vendor/bin/psalm --shepherd
.......
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
44
GithubAction for PHP-CS-Fixer
45
PHP Static Analysis in Github Actions
46
Laravel framework integration
47
Psalm plugin for Laravel
48
nunomaduro/larastan
49
參考資料
Phan
PHPStan
Psalm
PHPDoc
PHPStan Rules
GithubAction for PHP-CS-Fixer
Psalm on GitHub Workflow
Psalm plugin for Laravel
PHP Static Analysis in Github Actions
larastan
50
Thanks!
51

2021.laravelconf.tw.slides2

  • 1.
    Coding style, Static codeanalysis and PHP 1
  • 2.
    Outline About me What's Codingstyle? PSR-2與PSR-12程式碼⾵格標準。 What's static code analysis? PHPStan Psalm Phan CI/CD examples Laravel framework integration 2
  • 3.
    About me Peter Active opensource contributor An associate engineer DevOps Back-end System Architecture Researching Web Application Security PHP, Python and JavaScript Smart Grid Technology (2017~2021) Database, Data platform architecture (2021~) GitHub 3
  • 4.
    What's coding style? AKAProgramming style 4
  • 5.
  • 6.
  • 7.
    Coding style Founded byPHP-FIG PHP Framework Interop Group PSR-1 PSR-2 PSR-12 More standard docs https://www.php-fig.org https://github.com/php-fig https://github.com/php-fig/fig-standards/tree/master/accepted 7
  • 8.
    PSR-1 Overview Files MUSTuse only <?php and <?= tags. Files MUST use only UTF-8 without BOM for PHP code. Files SHOULD either declare symbols (classes, functions, constants, etc.) or cause side-effects (e.g. generate output, change .ini settings, etc.) but SHOULD NOT do both. Namespaces and classes MUST follow an "autoloading" PSR: [PSR-0, PSR- 4]. Class names MUST be declared in StudlyCaps. Class constants MUST be declared in all upper case with underscore separators. Method names MUST be declared in camelCase.   8
  • 9.
    PSR-2 Overview(Deprecated) Code MUSTfollow a "coding style guide" PSR [ ]. Code MUST use 4 spaces for indenting, not tabs. There MUST NOT be a hard limit on line length; the soft limit MUST be 120 characters; lines SHOULD be 80 characters or less. There MUST be one blank line after the namespace declaration, and there MUST be one blank line after the block of use declarations. Opening braces for classes MUST go on the next line, and closing braces MUST go on the next line after the body. Opening braces for methods MUST go on the next line, and closing braces MUST go on the next line after the body. Visibility MUST be declared on all properties and methods; abstract and final MUST be declared before the visibility; static MUST be declared after the visibility. Control structure keywords MUST have one space after them; method and function calls MUST NOT. Opening braces for control structures MUST go on the same line, and closing braces MUST go on the next line after the body. Opening parentheses for control structures MUST NOT have a space after them, and closing parentheses for control structures MUST NOT have a space before. PSR-1 9
  • 10.
    PSR-12 This specification extends,expands and replaces PSR-2, the coding style guide and requires adherence to PSR-1, the basic coding standard. 10
  • 11.
  • 12.
  • 13.
  • 14.
    PHP_CodeSniffer curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcs.phar chmod+x phpcs.phar mv phpcs.phar phpcs phpcs --help phpcs --standard=PSR2 src/ tests/ curl -OL https://squizlabs.github.io/PHP_CodeSniffer/phpcbf.phar chmod +x phpcbf.phar mv phpcbf.phar phpcbf phpcbf --help phpcbf --standard=PSR2 src/ tests/ 14
  • 15.
    phpcs --standard=PSR2 FILE: ...n-source-contributions/localized/src/Validation/LtValidation.php ---------------------------------------------------------------------- FOUND1 ERROR AFFECTING 1 LINE ---------------------------------------------------------------------- 31 | ERROR | [x] Use single instead of double quotes for simple | | strings. ---------------------------------------------------------------------- PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY ---------------------------------------------------------------------- FILE: ...is/build/open-source-contributions/localized/tests/bootstrap.php ---------------------------------------------------------------------- FOUND 1 ERROR AFFECTING 1 LINE ---------------------------------------------------------------------- 15 | ERROR | [x] Use single instead of double quotes for simple | | strings. ---------------------------------------------------------------------- PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY ---------------------------------------------------------------------- FILE: ...n-source-contributions/localized/src/Validation/BrValidation.php ---------------------------------------------------------------------- FOUND 2 ERRORS AFFECTING 1 LINE ---------------------------------------------------------------------- 196 | ERROR | [x] Use single instead of double quotes for simple | | strings. 196 | ERROR | [x] Use single instead of double quotes for simple | | strings. ---------------------------------------------------------------------- PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY ---------------------------------------------------------------------- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 15
  • 16.
  • 17.
  • 18.
    phpcs.xml <?xml version="1.0"?> <ruleset name="CodingStandard"> <arg name="basepath" value="."/> <arg name="colors"/> <arg value="sp"/> <config name="ignore_warnings_on_exit" value="1"/> <file>./src</file> <file>./tests</file> <rule ref="PSR2"></rule> <!-- <rule ref="PSR12"></rule> --> <rule ref="Squiz.Commenting.ClassComment"> <exclude name="Squiz.Commenting.ClassComment.TagNotAllowed"/> <type>warning</type> <exclude-pattern>*/tests/</exclude-pattern> </rule> <rule ref="Squiz.Commenting.ClassComment.Missing"> <type>warning</type> </rule> <rule ref="Squiz.Commenting.FunctionComment.Missing"> <type>warning</type> <exclude-pattern>*/config/</exclude-pattern> / 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 phpcs.xml.dist 18
  • 19.
    PHP-CS-Fixer curl -OL https://cs.symfony.com/download/php-cs-fixer-v2.phar phpphp-cs-fixer-v2.phar fix --dry-run --format=txt --verbose --diff --diff- format=udiff --config=.cs.php curl -OL https://cs.symfony.com/download/php-cs-fixer-v3.phar php php-cs-fixer-v3.phar fix --dry-run --format=txt --verbose --diff --diff- format=udiff --config=.cs.php 19
  • 20.
    .cs.php <?php return PhpCsFixerConfig::create() ->setUsingCache(false) ->setRiskyAllowed(true) //->setCacheFile(__DIR__ .'/.php_cs.cache') ->setRules([ '@PSR1' => true, '@PSR2' => true, '@Symfony' => true, 'psr4' => true, 'yoda_style' => false, 'array_syntax' => ['syntax' => 'short'], 'list_syntax' => ['syntax' => 'short'], 'concat_space' => ['spacing' => 'one'], 'cast_spaces' => ['space' => 'none'], 'compact_nullable_typehint' => true, 'increment_style' => ['style' => 'post'], 'declare_equal_normalize' => ['space' => 'single'], 'no_short_echo_tag' => true, 'protected_to_private' => false, 'phpdoc_align' => false, 'phpdoc_add_missing_param_annotation' => ['only_untyped' => false], 'phpdoc_order' => true, // psr-5 'phpdoc_no_empty_return' => false, 'align multiline comment' => true, // psr-5 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 PHP-CS-Fixer rules 20
  • 21.
  • 22.
    What's static codeanalysis? 22
  • 23.
    Static Code Analysis It'sthe analysis of computer software that is performed without actually executing programs. Dynamic code analysis is the analysis of computer software that is performed by executing programs. Unit tests, integration tests, system tests and acceptance tests use dynamic testing. 23
  • 24.
    Static Code Analysisfor PHP Psalm PHPStan Phan→The PHP Father recommended 24
  • 25.
  • 26.
    Installation composer require phpstan/phpstan:0.*--dev composer require vimeo/psalm:4.* --dev composer require phan/phan:5.* --dev 26
  • 27.
    Standard Checks there areno syntax errors; all the classes, methods, functions and constants exist; the variables exist; the hints in PHPDoc correspond to reality; there are no arguments or variables unused. Avoid copy-caste code errors and careless 27
  • 28.
    Data type checks Mostanalyzers allow to configure the level of strictness of checking and imitate strict_types: they check that String or Boolean aren’t passed to this function. 28
  • 29.
    Union types Most analyzersallow to configure the level of strictness of checking and imitate strict_types: they check that String or Boolean aren’t passed to this function. /** * @var string|int|bool $yes_or_no */ function isYes($yes_or_no) :bool { if (is_numeric($yes_or_no)) { return $yes_or_no > 0; } else { return strtoupper($yes_or_no) == 'YES'; } } 1 2 3 4 5 6 7 8 9 10 11 29
  • 30.
    False type Most analyzersallow to configure the level of strictness of checking and imitate strict_types: they check that String or Boolean aren’t passed to this function. /** @return int|bool */ function fwrite(...) { … } 1 2 3 4 30
  • 31.
    False type Error <?php /**@return resource|bool */ function open_file() { $fp = fopen('./composer.json', 'r'); if($fp === false) { return false; } return fwrite($fp, "some string"); } 1 2 3 4 5 6 7 8 9 10 11 lee@lee-VirtualBox:~/phpstan-example$ vendor/bin/phpstan analyse ./false_type.php --level=max -c phpstan ------ -------------------------------------------------------------------------------------------- Line false_type.php ------ -------------------------------------------------------------------------------------------- 4 Function open_file() never returns resource so it can be removed from the return typehint. 10 Function open_file() should return bool|resource but returns int|false. ------ -------------------------------------------------------------------------------------------- 1 2 3 4 5 6 7 31
  • 32.
    False type ErrorFix <?php /** @return int|false */ function open_file() { $fp = fopen('./composer.json', 'r'); if($fp === false) { return false; } return fwrite($fp, "some string"); } 1 2 3 4 5 6 7 8 9 10 11 lee@lee-VirtualBox:~/phpstan-example$ vendor/bin/phpstan analyse ./false_type.php --level=max -c phpstan.neon --no-progress --ansi [OK] No errors 1 2 3 4 32
  • 33.
    Array shapes <?php /** @returnarray */ function array_func(array $arr) { return $arr; } 1 2 3 4 5 6 lee@lee-VirtualBox:~/phpstan-example$ vendor/bin/phpstan analyse ./array_example.php --level=max -c phpstan.neon --no-progress --ansi ------ ----------------------------------------------------------------------------------------------- Line array_example.php ------ ----------------------------------------------------------------------------------------------- 4 Function array_func() has parameter $arr with no value type specified in iterable type array. 💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type 4 Function array_func() return type has no value type specified in iterable type array. 💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type ------ ----------------------------------------------------------------------------------------------- [ERROR] Found 2 errors 1 2 3 4 5 6 7 8 9 10 11 12 13 33
  • 34.
    Array shapes fix <?php /** @paramarray<string> $arr @return array<string> */ function array_func($arr) { return $arr; } 1 2 3 4 5 6 7 8 9 34
  • 35.
    Overview of staticcode analysis tools 35
  • 36.
    PHPStan Developed by Install it(the simplest way is via Composer) Configure it (optional) Run it Ondřej Mirtes lee@lee-VirtualBox:~/phpstan-example$ vendor/bin/phpstan analyse ./array_example.php 1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100% [OK] No errors 💡 Tip of the Day: PHPStan is performing only the most basic checks. You can pass a higher rule level through the --level option (the default and current level is 0) to analyse code more thoroughly. lee@lee-VirtualBox:~/phpstan-example$ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 36
  • 37.
    PHPStan Key Features PHPStanwill try to autoload unknown classes. If some classes are not autoloaded, it will not be able to find them and will return an error. If using magical methods via __call, __get, or __set, it can write a plug-in for PHPStan. In actual fact, PHPStan doesn’t only perform autoload in the case of unknown classes, but it also does so for all classes. Using for configuration.  No support for its PHPDoc tags @phpstan-var, @phpstan-return etc. PhpStan has a playground website . neon-format  https://phpstan.org 37
  • 38.
    Phan Developed by theEtsy company. First commits by Rasmus Lerdorf. Requiring the php-ast extension. Plugin example is available .  Creating a  file. Playground website is . here .phan/config.php available lee@lee-VirtualBox:~/phpstan-example$ php vendor/bin/phan array_example.php analyze ████████████████████████████████████████████████████████████ 100.0% 29MB/29MB lee@lee-VirtualBox:~/phpstan-example$ php vendor/bin/phan array_example.php analyze ████████████████████████████████████████████████████████████ 100.0% 28MB/31MB array_example.php:9 PhanSyntaxError syntax error, unexpected '}', expecting ';' (at column 1) 1 2 3 4 5 6 38
  • 39.
    Psalm Developed by theVimeo company Annotations code XML format file about configuration Type aliases array closure union type (for example, several classes or a class and other types) enum 39
  • 40.
  • 41.
    vendor/bin/psalm ░░░░░░░E░░░░E░E░░░EE░░░░░░░░░░░E░░░░E░░░░░E░E░░ ERROR: ParamNameMismatch -src/Element/Element.php:131:54 - Argument 2 of InnmindXmlElementElement:: public function replaceChild(int $position, Node $node): Node ERROR: ParamNameMismatch - src/Element/SelfClosingElement.php:36:54 - Argument 2 of InnmindXmlElement public function replaceChild(int $position, Node $node): Node ERROR: ParamNameMismatch - src/Node/CharacterData.php:43:54 - Argument 2 of InnmindXmlNodeCharacterD public function replaceChild(int $position, Node $node): Node ERROR: ParamNameMismatch - src/Node/Comment.php:43:54 - Argument 2 of InnmindXmlNodeComment::replace public function replaceChild(int $position, Node $node): Node ERROR: ParamNameMismatch - src/Node/Document.php:86:54 - Argument 2 of InnmindXmlNodeDocument::repla public function replaceChild(int $position, Node $node): Node 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 https://github.com/Innmind/XML/issues/2 41
  • 42.
  • 43.
    GitHub Workflow examples 1.Using Composer to install required development dependencies. 2. GithubAction for PHP-CS-Fixer. 3. PHP Static Analysis in Github Actions. 43
  • 44.
    composer install ....... psalm: runs-on: ubuntu-latest strategy: matrix: php-version:['7.4', '8.0'] name: 'Psalm' steps: - name: Checkout uses: actions/checkout@v2 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} extensions: mbstring, intl - name: Get Composer Cache Directory id: composer-cache run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache dependencies uses: actions/cache@v2 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} restore-keys: ${{ runner.os }}-composer- - name: Install Dependencies run: composer install - name: Psalm run: vendor/bin/psalm --shepherd ....... 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 44
  • 45.
  • 46.
    PHP Static Analysisin Github Actions 46
  • 47.
  • 48.
    Psalm plugin forLaravel 48
  • 49.
  • 50.
    參考資料 Phan PHPStan Psalm PHPDoc PHPStan Rules GithubAction forPHP-CS-Fixer Psalm on GitHub Workflow Psalm plugin for Laravel PHP Static Analysis in Github Actions larastan 50
  • 51.