🦸🏿♂️ Gato GraphQL hiện được biên dịch từ PHP 8.0 xuống 7.1
Một thời gian trước, tôi đã viết về nghệ thuật biên dịch chéo (transpile) mã 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
Biên dịch chéo mã PHP cho phép sử dụng các tính năng PHP mới nhất trong quá trình phát triển, nhưng vẫn phát hành plugin với mã đã được chuyển đổi sang phiên bản PHP cũ hơn cho môi trường production, nhằm tiếp cận được nhiều người dùng hơn.
Tôi đã dành vài tuần qua để tinh chỉnh thêm quy trình này cho plugin Gato GraphQL.
Tôi vui mừng thông báo rằng, từ nay, phiên bản PHP yêu cầu đã được nâng cấp lên PHP 8.0:

Vì plugin hiện có thể dựa vào PHP 8.0, tôi đã hoàn thành việc bổ sung kiểu dữ liệu cho tất cả các thuộc tính trong tất cả các lớp PHP trên toàn bộ codebase, bao gồm cả union types.
Tuyệt vời!
Dưới đây là tóm tắt tất cả các tính năng PHP 8.0 mới có sẵn khi phát triển plugin.
Các tính năng mới của PHP 8.0
Khi phát triển Gato GraphQL, các tính năng PHP 8.0 sau đây hiện đã có sẵn:
- Union types
- Kiểu giả
mixed - Kiểu trả về
static - Hằng số ma thuật
::classtrên các đối tượng - Biểu thức
match catchngoại lệ chỉ theo kiểu- Toán tử Null-safe
- Khởi tạo thuộc tính trong constructor của lớp
- Dấu phẩy cuối trong danh sách tham số và danh sách
usecủa closure
Hãy xem ví dụ về từng tính năng, cách chúng được sử dụng trong plugin khi phát triển, và chúng được biên dịch chéo thành gì khi tạo graphql-api.zip.
Union types
interface CustomPostTypeAPIInterface
{
public function createCustomPost(array $data): string | int | null | Error;
}Biên dịch chéo thành:
interface CustomPostTypeAPIInterface
{
public function createCustomPost(array $data)
}Kiểu giả mixed
interface CMSServiceInterface
{
public function getOption(string $option, mixed $default = false): mixed;
}Biên dịch chéo thành:
interface CMSServiceInterface
{
public function getOption(string $option, $default = false);
}Hằng số ma thuật ::class trên các đối tượng
foreach ($directiveResolvers as $directiveResolver) {
$directiveResolverName = $directiveResolver->getDirectiveName();
$this->directiveNameClasses[$directiveResolverName][] = $directiveResolver::class;
}Biên dịch chéo thành:
foreach ($directiveResolvers as $directiveResolver) {
$directiveResolverName = $directiveResolver->getDirectiveName();
$this->directiveNameClasses[$directiveResolverName][] = get_class($directiveResolver);
}Biểu thức 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;
}Biên dịch chéo thành:
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 ngoại lệ chỉ theo kiểu
try {
// ...
} catch (InvalidArgumentException) {
return sprintf(
'<p>%s</p>',
\__('Oops, the documentation for this module is not available', 'graphql-api')
);
}Biên dịch chéo thành:
try {
// ...
} catch (InvalidArgumentException $exception) {
return sprintf(
'<p>%s</p>',
\__('Oops, the documentation for this module is not available', 'graphql-api')
);
}Toán tử Null-safe
public function getSchemaDirectiveDeprecationDescription(TypeResolverInterface $typeResolver): ?string
{
return $this->getSchemaDefinitionResolver($typeResolver)?->getSchemaDirectiveDeprecationDescription($typeResolver);
}Biên dịch chéo thành:
public function getSchemaDirectiveDeprecationDescription(TypeResolverInterface $typeResolver): ?string
{
return $this->getSchemaDefinitionResolver($typeResolver) ? $this->getSchemaDefinitionResolver($typeResolver)->getSchemaDirectiveDeprecationDescription($typeResolver) : null;
}Khởi tạo thuộc tính trong constructor của lớp
abstract class AbstractEndpointResolver
{
function __construct(protected EndpointHelpers $endpointHelpers)
{
}
}Biên dịch chéo thành:
abstract class AbstractEndpointResolver
{
/**
* @var \GraphQLAPI\GraphQLAPI\Services\Helpers\EndpointHelpers
*/
protected $endpointHelpers;
function __construct(EndpointHelpers $endpointHelpers)
{
$this->endpointHelpers = $endpointHelpers;
}
}Dấu phẩy cuối trong danh sách tham số và danh sách use của closure
public function resolveFieldTypeResolverClass(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
switch ($fieldName) {
case 'accessControlLists':
return CustomPostTypeResolver::class;
}
return parent::resolveFieldTypeResolverClass(
$typeResolver,
$fieldName,
);
}Biên dịch chéo thành:
public function resolveFieldTypeResolverClass(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
switch ($fieldName) {
case 'accessControlLists':
return CustomPostTypeResolver::class;
}
return parent::resolveFieldTypeResolverClass($typeResolver, $fieldName);
}