tarantool/stubs
IDE stub definitions for the Tarantool PHP extension, providing accurate autocompletion, type hints, and static analysis for Tarantool classes and functions in Laravel or plain PHP projects.
tarantool/stubs ships nothing but PHPDoc-annotated class/function declarations for the Tarantool PHP extension (ext-tarantool). There is no runtime code. Its only job is to make your IDE and static analyser understand symbols that live in a C extension and therefore have no files on disk to index.
Minimal setup:
# The stub set is meaningless without knowing which extension version you target
pecl install tarantool # or confirm it is already loaded
php -m | grep tarantool
composer require --dev tarantool/stubs
Where to look first:
php --ri tarantool and php --re tarantool — dump the real classes, methods and signatures straight from the extension. This is your ground truth.stubs/ directory of the installed package — read it to confirm the exact namespace and class names the stubs declare, then diff mentally against the reflection output above. If they disagree, trust reflection.composer.json require-dev block — this belongs there, never in require.First real use case: you are writing a repository class that talks to Tarantool through the extension. Before the stubs, $client-> gives you nothing in PhpStorm and PHPStan reports "Call to an undefined method". After installing the stubs and pointing your tools at them, you get method completion, argument shapes, and return types for the client/connection and response objects.
Dev-only, tool-facing install. Keep the package in require-dev. Configure your analyser to scan the stub files rather than autoload them.
PHPStan:
parameters:
scanFiles:
- vendor/tarantool/stubs/stubs/*.php
Psalm (psalm.xml):
<psalm>
<stubs>
<file name="vendor/tarantool/stubs/stubs/tarantool.php"/>
</stubs>
</psalm>
Wrap the extension behind an interface. Extension classes are frequently final/internal and cannot be mocked. The stubs tell you the exact signatures, so write the adapter against them once:
interface TarantoolGateway
{
public function call(string $function, array $args = []): mixed;
}
final class ExtensionGateway implements TarantoolGateway
{
public function __construct(private \Tarantool\Client $client) {}
public function call(string $function, array $args = []): mixed
{
return $this->client->call($function, $args);
}
}
Now your business code depends on TarantoolGateway, unit tests use a hand-written fake, and only the thin adapter touches the extension. The stubs keep the adapter honest without needing the extension loaded in every CI job.
Split CI into static and runtime jobs.
static:
script:
- composer install
- vendor/bin/phpstan analyse # stubs make this pass without the extension
runtime:
script:
- pecl install tarantool
- vendor/bin/phpunit # extension actually present here
The static job installs the stub package and never loads the extension; the integration job loads the extension and does not need the stubs. Keeping these separate is the cleanest way to use a stub package.
Pin the stub version to your extension version. Stubs are hand-maintained; a signature that drifted from your installed extension produces false positives or false negatives. Add a comment next to the constraint recording the extension version it corresponds to, and upgrade the two together.
Generate your own when the package lags. If a method is missing from the stubs, dump and hand-write it:
foreach ((new ReflectionExtension('tarantool'))->getClasses() as $class) {
printf("%s\n", $class->getName());
foreach ($class->getMethods() as $m) {
printf(" %s(%s)\n", $m->getName(),
implode(', ', array_map(fn($p) => $p->getName(), $m->getParameters())));
}
}
Drop the result in your own stubs/ folder and add it to scanFiles alongside the package — you do not need to wait for upstream.
Cannot declare class X, because the name is already in use. Keep them out of autoload/autoload-dev, or add them to exclude-from-classmap. scanFiles is the safe route.Error by editing the stub.scanFiles/<stubs>. Composer's autoloader alone will not expose these to PHPStan or Psalm — they only scan configured paths.php --re tarantool after every extension upgrade and diff against the installed stubs.final or has internal-only constructors, the only testable seam is your own interface. Design for that up front rather than discovering it mid-refactor.composer show tarantool/stubs), then confirm the stub filename matches what you put in scanFiles. Stub packages often ship a single large file whose path changes between releases.stubs/ directory — a stub file is trivial to own and removes the dependency risk entirely.stubFiles (PHPStan) overrides individual function signatures without replacing the whole stub; this is the right tool when you need to correct one bad declaration rather than fork the project.How can I help you explore Laravel packages today?