Since Rector 0.12 a new RectorConfig
is available with simpler and easier to use config methods.
PHP 8 was released more than 2 weeks ago. Do you want to know what is new? Check colorful post series about PHP 8 news by Brent.
Do you want to upgrade your project today? Continue reading...
composer require rector/rector --dev
# create "rector.php"
vendor/bin/rector init
rector.php
with PHP 8 set:+use Rector\Set\ValueObject\SetList;
use Rector\Config\RectorConfig;
return function (RectorConfig $rectorConfig): void {
+ $rectorConfig->import(SetList::PHP_80);
};
vendor/bin/rector process src
How does such upgrade look in practise? See one of real pull-requests created with Rector:
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.
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'),
+};
get_class()
to Faster X::class
-get_class($object);
+$object::class;
class SomeClass
{
- public float $alcoholLimit;
-
- public function __construct(float $alcoholLimit = 0.0)
+ public function __construct(public float $alcoholLimit = 0.0)
{
- $this->alcoholLimit = $alcoholLimit;
}
}
class SomeClass
{
- final private function getter()
+ private function getter()
{
return $this;
}
}
class SomeClass
{
public function run($someObject)
{
- $someObject2 = $someObject->mayFail1();
- if ($someObject2 === null) {
- return null;
- }
-
- return $someObject2->mayFail2();
+ return $someObject->mayFail1()?->mayFail2();
}
}
catch()
is not Needed Anymore final class SomeClass
{
public function run()
{
try {
- } catch (Throwable $notUsedThrowable) {
+ } catch (Throwable) {
}
}
}
str_contains()
Function-$hasA = strpos('abc', 'a') !== false;
+$hasA = str_contains('abc', 'a');
str_starts_with()
Function-$isMatch = substr($haystack, 0, strlen($needle)) === $needle;
+$isMatch = str_starts_with($haystack, $needle);
str_ends_with()
Function-$isMatch = substr($haystack, -strlen($needle)) === $needle;
+$isMatch = str_ends_with($haystack, $needle);
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);
class SomeClass
{
- /**
- * @param array|int $number
- * @return bool|float
- */
- public function go($number)
+ public function go(array|int $number): bool|float
{
// ...
}
}
use Symfony\Component\Routing\Annotation\Route;
class SomeController
{
- /**
- * @Route(path="blog/{postSlug}", name="post")
- */
+ #[Route(path: 'blog/{postSlug}', name: 'post')]
public function __invoke(): Response
{
// ...
}
}
-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.
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
Update shivammathur/setup-php@v2
in your workflows:
jobs:
unit_tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
+ php-version: 7.4
- php-version: 8.0
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
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!