πŸ¦ΈπŸΏβ€β™‚οΈ Gato GraphQL is now transpiled from PHP 8.0 to 7.1


Some time ago, I wrote about the art of transpiling PHP code:

Transpiling PHP code enables to use the latest PHP features for development, yet release the plugin with its code converted to an older PHP version for production, as to target a bigger user base.

I spent the past few weeks further tuning this process for the Gato GraphQL plugin.

I'm happy to announce that, from now on, it's required PHP version has been upgraded, to PHP 8.0:

Upgrading to min PHP version 8.0

Since the plugin can now count on PHP 8.0, I've been able to complete adding a type to all properties for all PHP classes across the code base, now also including union types.

Awesome!

Here is the summary of all the new PHP 8.0 features available when developing the plugin.

New PHP 8.0 features

When developing Gato GraphQL, the following PHP 8.0 features are now available:

Let's see an example of each, how they are used in the plugin for development, and what they get transpiled down to when generating graphql-api.zip.

Union types

Code example:

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

Transpiled to:

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

mixed pseudo type

Code example:

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

Transpiled to:

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

::class magic constant on objects

Code example:

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

Transpiled to:

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

match expressions

Code example:

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

Transpiled to:

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 exceptions only by type

Code example:

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

Transpiled to:

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

Null-safe operator

Code example:

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

Transpiled to:

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

Class constructor property promotion

Code example:

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

Transpiled to:

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

Trailing commas in parameter lists and closure use lists

Code example:

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

Transpiled to:

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

Want more posts & tutorials?

Receive timely updates as we keep improving Gato GraphQL.

No spam. You can unsubscribe at any time.