PHP 8 发布于 2 周前。你想知道有什么新的特性吗?请查看:一文详解 PHP 8 的新特性
是否要立即升级您的项目?继续阅读...
In a Rush to Private Jet?
3 Steps to Upgrade in 5 mins
- Do it in 5 minutes:
composer require rector/rector --dev
# create "rector.php"
vendor/bin/rector init
- Update
rector.php
with PHP 8 set:
use Rector\Core\Configuration\Option;
+use Rector\Set\ValueObject\SetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::SETS, [
+ SetList::PHP_80,
]);
};
- Run Rector:
vendor/bin/rector process src
How does such upgrade look in practise? See one of real pull-requests created with Rector:
Smooth Upgrade?
This tutorial aims to prepare you for the expected required steps so that the upgrade will require the least effort possible. Follow the guide and get to PHP 8 like a walk in the park.
What Rector handles for You?
1. From switch()
to match()
-switch ($this->lexer->lookahead['type']) {
- case Lexer::T_SELECT:
- $statement = $this->SelectStatement();
- break;
-
- default:
- $this->syntaxError('SELECT, UPDATE or DELETE');
- break;
-}
+$statement = match ($this->lexer->lookahead['type']) {
+ Lexer::T_SELECT => $this->SelectStatement(),
+ default => $this->syntaxError('SELECT, UPDATE or DELETE'),
+};
2. From get_class()
to Faster X::class
-get_class($object);
+$object::class;
3. From Dummy Constructor to Promoted Properties
class SomeClass
{
- public float $alcoholLimit;
-
- public function __construct(float $alcoholLimit = 0.0)
+ public function __construct(public float $alcoholLimit = 0.0)
{
- $this->alcoholLimit = $alcoholLimit;
}
}
4. Private Final Methods are Not Allowed Anymore
class SomeClass
{
- final private function getter()
+ private function getter()
{
return $this;
}
}
5. Replace Null Checks with Null Safe Calls
class SomeClass
{
public function run($someObject)
{
- $someObject2 = $someObject->mayFail1();
- if ($someObject2 === null) {
- return null;
- }
-
- return $someObject2->mayFail2();
+ return $someObject->mayFail1()?->mayFail2();
}
}
6. Unused $variable in catch()
is not Needed Anymore
final class SomeClass
{
public function run()
{
try {
- } catch (Throwable $notUsedThrowable) {
+ } catch (Throwable) {
}
}
}
7. New str_contains()
Function
-$hasA = strpos('abc', 'a') !== false;
+$hasA = str_contains('abc', 'a');
8. New str_starts_with()
Function
-$isMatch = substr($haystack, 0, strlen($needle)) === $needle;
+$isMatch = str_starts_with($haystack, $needle);
9. New str_ends_with()
Function
-$isMatch = substr($haystack, -strlen($needle)) === $needle;
+$isMatch = str_ends_with($haystack, $needle);
10. New Stringable
Interface for
-class Name
+class Name implements Stringable
{
- public function __toString()
+ public function __toString(): string
{
return 'I can stringz';
}
}
Class that implements Stringable
can now be used in places, where string
type is needed:
function run(string $anyString)
{
// ...
}
$name = new Name('Kenny');
run($name);
11. From Union docblock types to Union PHP Declarations
class SomeClass
{
- /**
- * @param array|int $number
- * @return bool|float
- */
- public function go($number)
+ public function go(array|int $number): bool|float
{
// ...
}
}
12. Symfony Annotations to Attributes
use Symfony\Component\Routing\Annotation\Route;
class SomeController
{
- /**
- * @Route(path="blog/{postSlug}", name="post")
- */
+ #[Route('blog/{postSlug}', name: 'post')]
public function __invoke(): Response
{
// ...
}
}
13. From Doctrine Annotations to Attributes
-use Doctrine\Common\Annotations\Annotation\Target;
+use Attribute;
use Symfony\Component\Validator\Constraint;
-/**
- * @Annotation
- * @Target({"PROPERTY", "ANNOTATION"})
- */
+#[Attribute(Attribute::TARGET_PROPERTY)]
final class PHPConstraint extends Constraint
{
}
Then use in code with attributes:
final class DemoFormData
{
- /**
- * @PHPConstraint()
- */
+ #[PHPConstraint]
private string $content;
-
- /**
- * @PHPConstraint()
- */
+ #[PHPConstraint]
private string $config;
// ...
Don't bother with any of the steps above. Let Rector handle it.
Update Dockerfile
Do you use Docker? Upgrade images to new PHP version:
####
## Base stage, to empower cache
####
-FROM php:7.4-apache as base
+FROM php:8.0-apache as base
GitHub Actions
Update shivammathur/setup-php@v2
in your workflows:
jobs:
unit_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v2
with:
+ php-version: 7.4
- php-version: 8.0
Skip incompatible Coding Standard rules
These 3 rules are not compatible with PHP 8 yet. So better skip them in ecs.php
:
PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer
PhpCsFixer\Fixer\Operator\BinaryOperatorSpacesFixer
PhpCsFixer\Fixer\Operator\TernaryOperatorSpacesFixer
SlevomatCodingStandard\Sniffs\Classes\DisallowMultiPropertyDefinitionSniff
Resolve Hard Conflicts With composer install
Some packages didn't get to update their composer.json
. Be nice and help your fellow developers with a small pull-request:
{
"require": {
- "php": "^7.3"
+ "php": "^7.3|^8.0"
}
}
Other packages block PHP 8 upgrades from their own maintainers' ideology, even though the code runs on PHP 8. Watch an excellent 15-min video about this by Nikita Popov, the most active PHP core developer, and Nikolas Grekas, the same just for Symfony.
But ideology is not why we're here. We want to upgrade our project to PHP 8. Thanks to Composer 2, this can be easily solved:
-composer install
+composer update --ignore-platform-req php
Upgrade your CI workflows and Docker build scripts, and you're ready to go.
Happy coding!
via https://getrector.org/blog/2020/11/30/smooth-upgrade-to-php-8-in-diffs