PHP

Typed variables in PHP

vendor/bin/envless-env types writes a PHP class from your Envless variable names, types and visibility, so PHPStan, Psalm and your IDE catch a misspelt name or a bool used as a string.

vendor/bin/envless-env types reads the names, types and visibility of your variables, never their values, and writes a class with one static method per variable, typed by its declared type. A misspelt name or a bool used as a string then fails PHPStan, Psalm or your IDE instead of your deploy.

bash
vendor/bin/envless-env types --output app/Support/EnvlessEnv.php --namespace 'App\Support'
php
use App\Support\EnvlessEnv;

$databaseUrl = EnvlessEnv::DATABASE_URL();
$port = EnvlessEnv::PORT();
$debug = EnvlessEnv::DEBUG();
$browser = EnvlessEnv::client();

It is the PHP counterpart of envless types, which writes envless-env.d.ts for TypeScript. The class costs nothing at runtime: each method is one call to Env::string(), Env::number() or Env::boolean(). Commit it, it holds no secrets.

What it writes

php
<?php

declare(strict_types=1);

namespace App\Support;

use Envless\Env\Env;

final class EnvlessEnv
{
    public static function DATABASE_URL(): string
    {
        return Env::string('DATABASE_URL');
    }

    public static function PORT(): int|float
    {
        return Env::number('PORT');
    }

    public static function DEBUG(): bool
    {
        return Env::boolean('DEBUG');
    }

    /** @return array{DEBUG: bool} */
    public static function client(): array
    {
        return [
            'DEBUG' => Env::client()->boolean('DEBUG'),
        ];
    }
}

A string variable returns string, a boolean returns bool, and a number returns int|float, because a number reads back as an int when it is whole and a float when it is not. client() returns the variables marked client as a typed array shape, ready for json_encode() into a page.

Each method throws MissingVariableException when its variable is not set, like Env::get(). For a variable that may be absent, read it with Env::optional(). A variable named client or class, or one starting with two underscores, cannot be a method name, so the command skips it, says so on standard error, and it stays readable with Env::get().

Where the names come from

Under envless run, the command reads the manifest the CLI injected and makes no request, so your envless login session is all it needs:

bash
envless run -- vendor/bin/envless-env types --output app/Support/EnvlessEnv.php --namespace 'App\Support'

Outside it, the command fetches the metadata with the same machine credentials the loader uses: ENVLESS_TOKEN, with the project and environments from the flags, from ENVLESS_PROJECT and ENVLESS_ENV, or from .envless. No decryption key is needed. Every environment in .envless is read and merged in order, so a name that only exists in staging still gets a method, with the type of the first environment that declares it.

FlagPurpose
--output PATHThe file to write, EnvlessEnv.php by default
--class NAMEThe class name, EnvlessEnv by default
--namespace NAMEThe namespace, none by default. Match it to where --output sits in your Composer autoload
--project SLUGThe project, instead of ENVLESS_PROJECT or .envless
--product SLUGThe product, when the project slug exists in more than one
--env SLUGSComma separated environments, merged in order
--checkExit 1 when the file is missing or stale, and write nothing

Keeping it current

Run it again whenever you add, rename or retype a variable. In CI, --check fails the job when the committed file no longer matches Envless:

bash
envless run --env production -- vendor/bin/envless-env types --output app/Support/EnvlessEnv.php --namespace 'App\Support' --check

The file is written in the PER coding style, so PHP-CS-Fixer and Laravel Pint leave it alone and --check stays green. Leave it out of hand edits: the next run replaces it.