strict-types: مدیریت declare(strict_types=1) در PHP
ابزار خط فرمان که declare(strict_types=1) را به فایلهای PHP اضافه یا از آنها حذف میکند و فایلهای بدون آن را گزارش میدهد.
- نقش من
- نویسنده
- فناوریها
- PHP
- نشانی
- packagist.org/packages/sepehr-mohseni/strict-types
- کد
- github.com/sepehrmohseni/strict-types
PHP بهطور پیشفرض نوعهای ساده را خودش تبدیل میکند. اگر تابعی int بخواهد و شما رشتهٔ "5" به آن بدهید، PHP آن را به عدد تبدیل میکند. وقتی بالای یک فایل declare(strict_types=1); بنویسید، فراخوانیهایی که از داخل آن فایل انجام میشوند این تبدیل را انجام نمیدهند و بهجای آن TypeError میدهند. برای روشن کردن این حالت در یک پروژهٔ موجود باید این خط را به صدها فایل اضافه کنید و بعد هم مراقب باشید فایلهای تازه آن را داشته باشند. strict-types این دو کار را با سه فرمان انجام میدهد: add، remove و check.
strict-types یک ابزار خط فرمان PHP است و به Laravel یا فریمورک دیگری وابسته نیست. طبق composer.json با PHP 7.4 و PHP 8 کار میکند و وابستگی دیگری ندارد.
برای چه کسانی مناسب است
- پروژههایی که میخواهند strict typing را روی کد موجود روشن کنند.
- تیمهایی که میخواهند در CI جلوی اضافه شدن فایل بدون declaration را بگیرند.
- پروژههای Laravel، Symfony، WordPress، Drupal، Yii و CodeIgniter که پوشههای vendor و cache و قالبهایشان باید کنار گذاشته شوند. برای هر کدام یک preset آماده هست.
پیش از اجرا یک نکته را در نظر بگیرید: کدی که به تبدیل خودکار نوع تکیه کرده، بعد از افزودن declaration ممکن است TypeError بدهد. بعد از add تستهای پروژه را اجرا کنید.
نصب
composer require --dev sepehr-mohseni/strict-typesفایل اجرایی در vendor/bin/strict-types قرار میگیرد.
مثالها
# Add strict_types to files
./vendor/bin/strict-types add src/
# Check coverage
./vendor/bin/strict-types check .
# Remove strict_types
./vendor/bin/strict-types remove src/
# Generate config file
./vendor/bin/strict-types initفرمان add خط declare(strict_types=1); را درست بعد از تگ <?php در ابتدای فایل میگذارد. فایلهایی که از قبل این declaration را دارند دست نمیخورند. در پایان، جدولی از تعداد فایلهای پردازششده، تغییرکرده و فایلهایی که از قبل declaration داشتند نشان داده میشود.
# Laravel project with backup
./vendor/bin/strict-types add --preset=laravel --backup .
# Dry run to preview (-v lists the files)
./vendor/bin/strict-types add --dry-run -v app/
# Exclude files by pattern
./vendor/bin/strict-types add --exclude="*.test.php" src/
# Check and output JSON for CI
./vendor/bin/strict-types check --json src/ > report.json
# Only list files that are missing the declaration
./vendor/bin/strict-types check --missing-only app/گزینههای اصلی:
--dry-runتغییرات را نشان میدهد ولی فایلی را عوض نمیکند.--backupپیش از تغییر هر فایل یک نسخهٔ.bakکنار آن میسازد.--no-recursiveفقط فایلهای همان پوشه را پردازش میکند و وارد زیرپوشهها نمیشود.--preset=<name>یکی از presetهای فریمورک را به کار میبرد.--exclude=<pattern>فایلهایی را که با الگو جور درمیآیند کنار میگذارد و میتوانید آن را چند بار تکرار کنید.--jsonخروجیcheckرا JSON میکند.-vجزئیات بیشتر و-qخروجی کمتر نشان میدهد.
استفاده در CI
# GitHub Actions
- name: Check strict_types
run: ./vendor/bin/strict-types check --json . > coverage.jsonاگر حتی یک فایل declaration نداشته باشد، check با کد خروج 1 تمام میشود و این مرحله در CI شکست میخورد. خروجی JSON یک بخش summary با تعداد کل فایلها، تعداد فایلهای با و بدون declaration، تعداد خطاها و درصد پوشش دارد، و یک فهرست files که وضعیت هر فایل را نشان میدهد.
پیکربندی
init فایل .strict-types.json را میسازد. اگر این فایل در پوشهای باشد که ابزار را از آن اجرا میکنید، خودکار خوانده میشود. با --config=path هم میتوانید فایل دیگری بدهید. همهٔ کلیدها در فایل نمونهٔ .strict-types.json.example مخزن آمدهاند:
{
"exclude_patterns": ["*.blade.php", "*.test.php"],
"exclude_directories": ["vendor", "node_modules", ".git", "storage", "cache"],
"exclude_files": [],
"dry_run": false,
"backup": true,
"backup_extension": ".bak",
"recursive": true,
"declaration_style": "standard",
"preset": null
}- پوشههای
vendor،node_modules،.git،storageوcacheهمیشه کنار گذاشته میشوند وexclude_directoriesبه این فهرست اضافه میشود. declaration_styleبا مقدارstandardخطdeclare(strict_types=1);و با مقدارspacedخطdeclare( strict_types = 1 );را مینویسد. همین را با گزینهٔ--styleهم میتوانید بدهید.exclude_filesنام فایلهایی است که باید کنار گذاشته شوند.
presetها
اگر --preset ندهید، add و check نوع پروژه را از روی فایلهای پوشهای که به فرمان دادهاید تشخیص میدهند. مثلاً وجود artisan و bootstrap/app.php در آن پوشه یعنی Laravel، پس این تشخیص وقتی کار میکند که ریشهٔ پروژه را بدهید. هر preset این موارد را کنار میگذارد:
- preset
laravelفایلهای*.blade.phpو پوشههایstorage،bootstrap/cacheوpublicرا کنار میگذارد. - preset
symfonyپوشههایvarوpublicرا کنار میگذارد. - preset
wordpressپوشههایwp-adminوwp-includesرا کنار میگذارد. - preset
drupalپوشهٔcoreرا کنار میگذارد. - preset
yiiپوشههایruntimeوweb/assetsرا کنار میگذارد. - preset
codeigniterپوشههایsystemوwritableرا کنار میگذارد.
تفاوت با گزینههای دیگر
PHP CS Fixer قانونی به نام declare_strict_types دارد. در مستندات آن، این قانون risky علامت خورده است و گزینهٔ strategy آن سه مقدار add_when_missing، enforce (پیشفرض) و remove را میپذیرد. اگر PHP CS Fixer را از قبل در پروژه دارید، روشن کردن همین قانون احتمالاً کافی است.
strict-types ابزار جداگانهای است که فقط همین یک کار را انجام میدهد و به PHP 7.4 یا بالاتر نیاز دارد. presetهای فریمورک، پشتیبان .bak، گزارش درصد پوشش و خروجی JSON با کد خروج مناسب برای CI را هم دارد.
پرسشهای پرتکرار
فایلهایی که از قبل declaration دارند چه میشوند؟
دست نمیخورند. add آنها را رد میکند و در جدول پایانی جداگانه میشمارد.
اجرای add روی پروژه امن است؟
پیش از هر چیز با --dry-run -v ببینید کدام فایلها تغییر میکنند و با --backup از فایلها نسخهٔ پشتیبان بگیرید. اگر فایلی با <?php شروع نشود، مثلاً قالبی که با HTML شروع میشود، ابزار یک <?php و declaration به ابتدای آن اضافه میکند. اینجور فایلها را با --exclude یا exclude_patterns کنار بگذارید.
چطور تغییرات add را برگردانم؟
اگر با --backup اجرا کرده باشید، نسخهٔ قبلی هر فایل با پسوند .bak کنارش هست. فرمان remove هم declaration را حذف میکند، ولی از همهٔ فایلهای آن مسیر، از جمله فایلهایی که پیش از اجرای add هم آن را داشتند. برای برگرداندن دقیق، نسخههای .bak یا git را به کار ببرید.
با کدام نسخههای PHP کار میکند؟
طبق composer.json، PHP 7.4 و همهٔ نسخههای PHP 8.