博客

🦸🏿‍♂️ Gato GraphQL 现已从 PHP 8.0 转译至 7.1

Leonardo Losoviz
作者:Leonardo Losoviz ·

前不久,我写了几篇关于 PHP 代码转译技术的文章:

转译 PHP 代码使我们能够在开发时使用最新的 PHP 特性,同时在发布插件时将代码转换为更旧的 PHP 版本用于生产环境,从而覆盖更广泛的用户群体。

过去几周,我一直在为 Gato GraphQL 插件进一步优化这一流程。

我很高兴地宣布,从现在起,所需的 PHP 版本已升级至 PHP 8.0:

升级到最低 PHP 版本 8.0

由于插件现在可以依赖 PHP 8.0,我已经能够完成为整个代码库中所有 PHP 类的所有属性添加类型的工作,现在也包括联合类型。

太棒了!

以下是开发插件时所有可用的 PHP 8.0 新特性汇总。

PHP 8.0 新特性

在开发 Gato GraphQL 时,以下 PHP 8.0 特性现已可用:

让我们来看看每个特性的示例,它们在插件开发中如何使用,以及在生成 graphql-api.zip 时如何被转译。

联合类型

代码示例:

interface CustomPostTypeAPIInterface
{
  public function createCustomPost(array $data): string | int | null | Error;
}

转译后:

interface CustomPostTypeAPIInterface
{
  public function createCustomPost(array $data)
}

mixed 伪类型

代码示例:

interface CMSServiceInterface
{
  public function getOption(string $option, mixed $default = false): mixed;
}

转译后:

interface CMSServiceInterface
{
  public function getOption(string $option, $default = false);
}

对象上的 ::class 魔术常量

代码示例:

foreach ($directiveResolvers as $directiveResolver) {
  $directiveResolverName = $directiveResolver->getDirectiveName();
  $this->directiveNameClasses[$directiveResolverName][] = $directiveResolver::class;
}

转译后:

foreach ($directiveResolvers as $directiveResolver) {
  $directiveResolverName = $directiveResolver->getDirectiveName();
  $this->directiveNameClasses[$directiveResolverName][] = get_class($directiveResolver);
}

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;
}

转译后:

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 异常

代码示例:

try {
  // ...
} catch (InvalidArgumentException) {
  return sprintf(
    '<p>%s</p>',
    \__('Oops, the documentation for this module is not available', 'graphql-api')
  );
}

转译后:

try {
  // ...
} catch (InvalidArgumentException $exception) {
  return sprintf(
    '<p>%s</p>',
    \__('Oops, the documentation for this module is not available', 'graphql-api')
  );
}

Null 安全运算符

代码示例:

public function getSchemaDirectiveDeprecationDescription(TypeResolverInterface $typeResolver): ?string
{
  return $this->getSchemaDefinitionResolver($typeResolver)?->getSchemaDirectiveDeprecationDescription($typeResolver);
}

转译后:

public function getSchemaDirectiveDeprecationDescription(TypeResolverInterface $typeResolver): ?string
{
  return $this->getSchemaDefinitionResolver($typeResolver) ? $this->getSchemaDefinitionResolver($typeResolver)->getSchemaDirectiveDeprecationDescription($typeResolver) : null;
}

类构造函数属性提升

代码示例:

abstract class AbstractEndpointResolver
{
  function __construct(protected EndpointHelpers $endpointHelpers)
  {
  }
}

转译后:

 abstract class AbstractEndpointResolver
 {
  /**
   * @var \GraphQLAPI\GraphQLAPI\Services\Helpers\EndpointHelpers
   */
  protected $endpointHelpers;
 
  function __construct(EndpointHelpers $endpointHelpers)
  {
    $this->endpointHelpers = $endpointHelpers;
  }
}

参数列表和闭包 use 列表中的尾逗号

代码示例:

public function resolveFieldTypeResolverClass(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
    switch ($fieldName) {
        case 'accessControlLists':
            return CustomPostTypeResolver::class;
    }
 
    return parent::resolveFieldTypeResolverClass(
        $typeResolver,
        $fieldName,
    );
}

转译后:

public function resolveFieldTypeResolverClass(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
    switch ($fieldName) {
        case 'accessControlLists':
            return CustomPostTypeResolver::class;
    }
 
    return parent::resolveFieldTypeResolverClass($typeResolver, $fieldName);
}

订阅我们的新闻通讯

及时了解 Gato GraphQL 的所有更新。