phalcon/cphalcon · error · Phalcon\Container\Exceptions\CannotResolveParameter

Cannot resolve parameter '${param}' for '{className}'

Error message

Cannot resolve parameter '${param}' for '{className}'

What it means

When autowiring a class-based definition, freeze() asks the Resolver to supply constructor parameters. A parameter that is not a class the container has (or can autowire), is not optional, and has no default value triggers CannotResolveParameter, naming the parameter and its declaring class. Scalar/untyped required constructor args are the classic cause.

Source

Thrown at phalcon/Container/Resolver/Resolver.zep:180

            let typeName = type->getName();

            if (method_exists(ioc, "has") && ioc->has(typeName)) {
                return ioc->get(typeName);
            }
        }

        if (parameter->isOptional()) {
            if (parameter->isDefaultValueAvailable()) {
                return parameter->getDefaultValue();
            }

            return null;
        }

        let declaringClass = parameter->getDeclaringClass();
        let declaringName  = declaringClass !== null ? declaringClass->getName() : "unknown";

        throw new CannotResolveParameter(
            parameter->getName(),
            declaringName
        );
    }

    public function resolveParameters(
        object ioc,
        array parameters,
        array arguments
    ) -> array {
        var resolved, position, parameter, name;

        let resolved = [];

        for position, parameter in parameters {
            let name = parameter->getName();

            if (array_key_exists(position, arguments)) {

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Provide the argument explicitly: $container->set(Svc::class, Svc::class)->setConstructorArgs([new Env('API_KEY')])
  2. Bind any missing interface: $container->set(CacheInterface::class, RedisCache::class)
  3. Give the parameter a default value or make it optional if it is genuinely optional
  4. Move scalar config out of constructors into a config object that is itself resolvable from the container

Example fix

// before
class PaymentService {
    public function __construct(private string $apiKey) {}
}
$container->setAutowire(true);
$container->get(PaymentService::class); // CannotResolveParameter: $apiKey

// after
$container->set(PaymentService::class, PaymentService::class)
    ->setConstructorArgs([new \Phalcon\Container\Resolver\Lazy\Env('PAYMENT_KEY')]);
$container->get(PaymentService::class);
Defensive patterns

Strategy: validation

Validate before calling

// Verify all constructor params of a class are satisfiable before autowiring
function autowirable(\Phalcon\Container\Container $c, string $class): bool
{
    $ctor = (new \ReflectionClass($class))->getConstructor();
    if ($ctor === null) {
        return true;
    }
    foreach ($ctor->getParameters() as $p) {
        if ($p->isOptional()) {
            continue;
        }
        $type = $p->getType();
        if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) {
            if (!$c->has($type->getName())) {
                return false;
            }
            continue;
        }
        return false; // required scalar param: cannot be autowired
    }
    return true;
}

Try / catch

use Phalcon\Container\Exceptions\CannotResolveParameter;

try {
    $svc = $container->get(PaymentService::class);
} catch (CannotResolveParameter $e) {
    // message names the param and class; register an explicit binding and retry
    $container->set(PaymentService::class, PaymentService::class)
        ->setConstructorArgs([getenv('PAYMENT_KEY')]);
    $svc = $container->get(PaymentService::class);
}

Prevention

When it happens

Trigger: class PaymentService { public function __construct(string $apiKey) {} } resolved via get(PaymentService::class) with no constructorArgs; a required interface-typed parameter whose implementation was never set(); a required param typed to a class that is itself unresolvable.

Common situations: Autowiring controllers or handlers with scalar config (API keys, paths, DSN parts); forgetting to bind an interface; adding a new required constructor argument during refactoring without updating registrations.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/4df3fbaa2638e321. Report an issue: GitHub.