要兼顧 PHP 開發品質,在 commit 之前可以用一些套件檢測,不管是否有符合 coding convention 或是有沒有語法上的錯誤,都可以預防性的監測。
composer require --dev phpstan/phpstan squizlabs/php_codesniffer friendsofphp/php-cs-fixer phpmd/phpmd phpunit/phpunit brianium/paratest
搭配 Makefile
可以減少每次執行要打的指令,此配置是針對 Laravel,可依照不同環境內容變動。
Makefile
| fix-code-format: |
| vendor/bin/php-cs-fixer fix --verbose |
| |
| code-style-check: |
| vendor/bin/phpstan analyse |
| vendor/bin/phpcs --standard=PSR12 app tests |
| vendor/bin/php-cs-fixer fix --dry-run |
| vendor/bin/phpmd app,config,database,routes,tests text phpmd.xml |
| |
| test: code-style-check |
| vendor/bin/paratest --colors --processes 4 --runner=WrapperRunner |
phpstan.neon
| parameters: |
| paths: |
| - app |
| excludePaths: |
| - app/Http/Middleware/Authenticate.php |
| - app/Providers/RouteServiceProvider.php |
| |
| level: 5 |
| |
| parallel: |
| processTimeout: 60.0 |
| maximumNumberOfProcesses: 32 |
| minimumNumberOfJobsPerProcess: 2 |
| |
| checkMissingIterableValueType: false |
.php-cs-fixer.php
| <?php |
| |
| use PhpCsFixer\Config; |
| use PhpCsFixer\Finder; |
| |
| $rules = [ |
| 'array_syntax' => ['syntax' => 'short'], |
| 'binary_operator_spaces' => ['default' => 'single_space'], |
| 'blank_line_after_namespace' => true, |
| 'blank_line_after_opening_tag' => true, |
| 'blank_line_before_statement' => true, |
| 'cast_spaces' => true, |
| 'class_definition' => true, |
| 'declare_equal_normalize' => true, |
| 'elseif' => true, |
| 'encoding' => true, |
| 'full_opening_tag' => true, |
| 'function_declaration' => true, |
| 'type_declaration_spaces' => true, |
| 'lowercase_cast' => true, |
| 'heredoc_to_nowdoc' => true, |
| 'include' => true, |
| 'indentation_type' => true, |
| 'lowercase_keywords' => true, |
| 'magic_constant_casing' => true, |
| 'method_argument_space' => true, |
| 'phpdoc_separation' => false, |
| 'native_function_casing' => true, |
| 'no_alias_functions' => true, |
| 'no_blank_lines_after_class_opening' => true, |
| 'no_blank_lines_after_phpdoc' => true, |
| 'multiline_whitespace_before_semicolons' => ['strategy' => 'no_multi_line'], |
| 'no_closing_tag' => true, |
| 'no_empty_phpdoc' => true, |
| 'no_empty_statement' => true, |
| 'no_leading_import_slash' => true, |
| 'no_leading_namespace_whitespace' => true, |
| 'no_multiline_whitespace_around_double_arrow' => true, |
| 'no_short_bool_cast' => true, |
| 'no_singleline_whitespace_before_semicolons' => true, |
| 'no_spaces_after_function_name' => true, |
| 'no_spaces_around_offset' => ['positions' => ['inside']], |
| 'spaces_inside_parentheses' => true, |
| 'no_trailing_comma_in_singleline' => true, |
| 'no_trailing_whitespace' => true, |
| 'no_trailing_whitespace_in_comment' => true, |
| 'no_unneeded_control_parentheses' => true, |
| 'no_unreachable_default_argument_value' => true, |
| 'no_unused_imports' => true, |
| 'no_useless_return' => true, |
| 'no_whitespace_before_comma_in_array' => true, |
| 'no_whitespace_in_blank_line' => true, |
| 'normalize_index_brace' => true, |
| 'not_operator_with_successor_space' => true, |
| 'object_operator_without_whitespace' => true, |
| 'ordered_class_elements' => true, |
| 'ordered_imports' => ['sort_algorithm' => 'alpha'], |
| 'phpdoc_indent' => true, |
| 'phpdoc_line_span' => ['const' => 'multi', 'method' => 'multi', 'property' => 'single'], |
| 'phpdoc_no_access' => true, |
| 'phpdoc_no_useless_inheritdoc' => true, |
| 'phpdoc_order' => true, |
| 'phpdoc_scalar' => true, |
| 'phpdoc_single_line_var_spacing' => true, |
| 'phpdoc_to_comment' => true, |
| 'phpdoc_trim' => true, |
| 'phpdoc_no_alias_tag' => ['replacements' => ['type' => 'var']], |
| 'phpdoc_types' => true, |
| 'phpdoc_var_without_name' => true, |
| 'no_mixed_echo_print' => ['use' => 'echo'], |
| 'self_accessor' => true, |
| 'short_scalar_cast' => true, |
| 'simplified_null_return' => true, |
| 'single_blank_line_at_eof' => true, |
| 'blank_lines_before_namespace' => true, |
| 'single_class_element_per_statement' => true, |
| 'single_import_per_statement' => true, |
| 'single_line_after_imports' => true, |
| 'single_quote' => true, |
| 'space_after_semicolon' => true, |
| 'standardize_not_equals' => true, |
| 'switch_case_semicolon_to_colon' => true, |
| 'switch_case_space' => true, |
| 'ternary_operator_spaces' => true, |
| 'trailing_comma_in_multiline' => ['elements' => ['arrays']], |
| 'trim_array_spaces' => true, |
| 'unary_operator_spaces' => true, |
| 'visibility_required' => true, |
| 'whitespace_after_comma_in_array' => true, |
| 'concat_space' => ['spacing' => 'one'], |
| 'single_space_around_construct' => true, |
| 'control_structure_braces' => true, |
| 'braces_position' => true, |
| 'control_structure_continuation_position' => true, |
| 'declare_parentheses' => true, |
| 'statement_indentation' => true, |
| ]; |
| |
| $excludes = [ |
| 'bootstrap/cache', |
| 'storage', |
| 'vendor', |
| 'node_modules', |
| ]; |
| |
| $finder = PhpCsFixer\Finder::create() |
| ->in(__DIR__) |
| ->exclude($excludes) |
| ->notName('*.xml') |
| ->notName('*.yml'); |
| |
| $config = new PhpCsFixer\Config(); |
| $config->setRiskyAllowed(true) |
| ->setIndent(' ') |
| ->setLineEnding("\n") |
| ->setRules($rules) |
| ->setUsingCache(true) |
| ->setFinder($finder); |
| |
| return $config; |
phpmd.xml
| <?xml version="1.0" encoding="UTF-8"?> |
| <ruleset name="Netask rule set" |
| xmlns="http://pmd.sf.net/ruleset/1.0.0" |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd" |
| xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"> |
| <description>Netask code style rule set |
| </description> |
| <rule ref="rulesets/codesize.xml/CyclomaticComplexity"/> |
| <rule ref="rulesets/codesize.xml/NPathComplexity"/> |
| <rule ref="rulesets/codesize.xml/ExcessiveMethodLength"/> |
| <rule ref="rulesets/codesize.xml/ExcessiveClassLength"/> |
| <rule ref="rulesets/codesize.xml/ExcessiveParameterList"/> |
| <rule ref="rulesets/codesize.xml/ExcessivePublicCount"> |
| <properties> |
| <property name="minimum" value="30"/> |
| </properties> |
| </rule> |
| <rule ref="rulesets/codesize.xml/TooManyFields"> |
| <properties> |
| <property name="maxfields" value="20"/> |
| </properties> |
| </rule> |
| <rule ref="rulesets/codesize.xml/TooManyMethods"/> |
| <rule ref="rulesets/codesize.xml/ExcessiveClassComplexity"> |
| <properties> |
| <property name="maximum" value="30"/> |
| </properties> |
| </rule> |
| <rule ref="rulesets/controversial.xml"/> |
| <rule ref="rulesets/design.xml"/> |
| <rule ref="rulesets/naming.xml/ShortVariable"/> |
| <rule ref="rulesets/naming.xml/LongVariable"> |
| <properties> |
| <property name="maximum" value="30"/> |
| </properties> |
| </rule> |
| <rule ref="rulesets/naming.xml/ShortMethodName"> |
| <properties> |
| <property name="minimum" value="2"/> |
| </properties> |
| </rule> |
| <rule ref="rulesets/naming.xml/ConstructorWithNameAsEnclosingClass"/> |
| <rule ref="rulesets/naming.xml/ConstantNamingConventions"/> |
| <rule ref="rulesets/naming.xml/BooleanGetMethodName"/> |
| <rule ref="rulesets/unusedcode.xml/UnusedPrivateField" /> |
| <rule ref="rulesets/unusedcode.xml/UnusedLocalVariable" /> |
| |
| <exclude-pattern>app/Console/Kernel.php</exclude-pattern> |
| <exclude-pattern>app/Services/Service.php</exclude-pattern> |
| <exclude-pattern>tests/TestCase.php</exclude-pattern> |
| </ruleset> |
phpunit.xml
| <?xml version="1.0" encoding="UTF-8"?> |
| <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd" |
| bootstrap="vendor/autoload.php" |
| colors="true" |
| > |
| <testsuites> |
| <testsuite name="Unit"> |
| <directory suffix="Test.php">./tests/Unit</directory> |
| </testsuite> |
| <testsuite name="Feature"> |
| <directory suffix="Test.php">./tests/Feature</directory> |
| </testsuite> |
| </testsuites> |
| <coverage processUncoveredFiles="true"> |
| <include> |
| <directory suffix=".php">./app</directory> |
| </include> |
| </coverage> |
| <php> |
| <server name="APP_ENV" value="testing"/> |
| <server name="BCRYPT_ROUNDS" value="4"/> |
| <server name="CACHE_DRIVER" value="array"/> |
| |
| |
| <server name="MAIL_MAILER" value="array"/> |
| <server name="QUEUE_CONNECTION" value="sync"/> |
| <server name="SESSION_DRIVER" value="array"/> |
| <server name="TELESCOPE_ENABLED" value="false"/> |
| </php> |
| </phpunit> |