ブログ

🦸🏿‍♂️ 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 のすべてのアップデートを把握しましょう。