🦸🏿♂️ Gato GraphQL agora é transpilado de PHP 8.0 para 7.1
Há algum tempo, escrevi sobre a arte de transpilar código PHP:
- Transpiling PHP code from 8.0 to 7.x via Rector
- Coding in PHP 7.4 and deploying to 7.1 via Rector and GitHub Actions
Transpilar código PHP permite usar os recursos mais recentes do PHP para o desenvolvimento, mas ainda assim publicar o plugin com o código convertido para uma versão mais antiga do PHP para produção, de forma a atingir uma base de usuários maior.
Passei as últimas semanas refinando ainda mais esse processo para o plugin Gato GraphQL.
Tenho o prazer de anunciar que, a partir de agora, a versão mínima de PHP exigida foi atualizada para PHP 8.0:

Como o plugin agora pode contar com PHP 8.0, consegui concluir a adição de um tipo a todas as propriedades de todas as classes PHP em toda a base de código, incluindo agora também os union types.
Incrível!
Aqui está o resumo de todos os novos recursos do PHP 8.0 disponíveis ao desenvolver o plugin.
Novos recursos do PHP 8.0
Ao desenvolver o Gato GraphQL, os seguintes recursos do PHP 8.0 estão agora disponíveis:
- Union types
- Pseudotipo
mixed - Tipo de retorno
static - Constante mágica
::classem objetos - Expressões
match catchde exceções somente por tipo- Operador Null-safe
- Promoção de propriedades no construtor de classe
- Vírgulas finais em listas de parâmetros e listas
usede closures
Vamos ver um exemplo de cada um, como são usados no plugin para o desenvolvimento e em que são transpilados ao gerar o graphql-api.zip.
Union types
interface CustomPostTypeAPIInterface
{
public function createCustomPost(array $data): string | int | null | Error;
}Transpilado para:
interface CustomPostTypeAPIInterface
{
public function createCustomPost(array $data)
}Pseudotipo mixed
interface CMSServiceInterface
{
public function getOption(string $option, mixed $default = false): mixed;
}Transpilado para:
interface CMSServiceInterface
{
public function getOption(string $option, $default = false);
}Constante mágica ::class em objetos
foreach ($directiveResolvers as $directiveResolver) {
$directiveResolverName = $directiveResolver->getDirectiveName();
$this->directiveNameClasses[$directiveResolverName][] = $directiveResolver::class;
}Transpilado para:
foreach ($directiveResolvers as $directiveResolver) {
$directiveResolverName = $directiveResolver->getDirectiveName();
$this->directiveNameClasses[$directiveResolverName][] = get_class($directiveResolver);
}Expressões match
public function getSchemaFieldType(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
$ret = match($fieldName) {
'accessControlLists' => TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID),
'cacheControlLists' => TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID),
'fieldDeprecationLists' => TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID),
'schemaConfigurations' => TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID),
default => parent::getSchemaFieldType($typeResolver, $fieldName),
};
return $ret;
}Transpilado para:
public function getSchemaFieldType(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
switch ($fieldName) {
case 'accessControlLists':
$ret = TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID);
break;
case 'cacheControlLists':
$ret = TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID);
break;
case 'fieldDeprecationLists':
$ret = TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID);
break;
case 'schemaConfigurations':
$ret = TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID);
break;
default:
$ret = parent::getSchemaFieldType($typeResolver, $fieldName);
break;
}
return $ret;
}catch de exceções somente por tipo
try {
// ...
} catch (InvalidArgumentException) {
return sprintf(
'<p>%s</p>',
\__('Oops, the documentation for this module is not available', 'graphql-api')
);
}Transpilado para:
try {
// ...
} catch (InvalidArgumentException $exception) {
return sprintf(
'<p>%s</p>',
\__('Oops, the documentation for this module is not available', 'graphql-api')
);
}Operador Null-safe
public function getSchemaDirectiveDeprecationDescription(TypeResolverInterface $typeResolver): ?string
{
return $this->getSchemaDefinitionResolver($typeResolver)?->getSchemaDirectiveDeprecationDescription($typeResolver);
}Transpilado para:
public function getSchemaDirectiveDeprecationDescription(TypeResolverInterface $typeResolver): ?string
{
return $this->getSchemaDefinitionResolver($typeResolver) ? $this->getSchemaDefinitionResolver($typeResolver)->getSchemaDirectiveDeprecationDescription($typeResolver) : null;
}Promoção de propriedades no construtor de classe
abstract class AbstractEndpointResolver
{
function __construct(protected EndpointHelpers $endpointHelpers)
{
}
}Transpilado para:
abstract class AbstractEndpointResolver
{
/**
* @var \GraphQLAPI\GraphQLAPI\Services\Helpers\EndpointHelpers
*/
protected $endpointHelpers;
function __construct(EndpointHelpers $endpointHelpers)
{
$this->endpointHelpers = $endpointHelpers;
}
}Vírgulas finais em listas de parâmetros e listas use de closures
public function resolveFieldTypeResolverClass(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
switch ($fieldName) {
case 'accessControlLists':
return CustomPostTypeResolver::class;
}
return parent::resolveFieldTypeResolverClass(
$typeResolver,
$fieldName,
);
}Transpilado para:
public function resolveFieldTypeResolverClass(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
switch ($fieldName) {
case 'accessControlLists':
return CustomPostTypeResolver::class;
}
return parent::resolveFieldTypeResolverClass($typeResolver, $fieldName);
}