InterMix is a lightweight, high-performance PHP dependency injection and runtime utility toolkit. Dependency injection and invocation are the primary capabilities, supported by compiled resolution, Closure serialization, Fence, and fluent Remix utilities.
Global helper functions are optional: core APIs are namespaced and helper loading is opt-in.
- Dependency Injection (DI) — PSR-11 compliant container with:
- attribute-based injection
- scoped lifetimes
- lazy loading
- environment-specific overrides
- debug tracing & definition-cache integration via assignable PSR-6 pool
- Closure Serialization — Versioned unsigned and explicitly signed Closure payloads
- Fence — Enforce singleton-style class safety
- Remix — Fluent traits, proxies, and global helper functions
- MacroMix — Dynamically extend objects or classes with macros
- Global Utilities — Like
pipe(),retry(),measure()and more
composer require infocyph/intermixOptional global helpers:
require_once __DIR__ . '/vendor/infocyph/intermix/src/functions.php';Current InterMix releases require PHP 8.4 or newer, as declared by composer.json.
use function Infocyph\InterMix\container;
$c = container();
$c->definitions()->bind('now', fn () => new DateTimeImmutable());
echo $c->get('now')->format('c');Enable autowiring with attributes:
$c->options()->setOptions(
injection: true,
methodAttributes: true,
propertyAttributes: true
);Tag-based resolution:
$c->definitions()->bind('a', A::class, tags: ['service']);
$c->definitions()->bind('b', B::class, tags: ['service']);
foreach ($c->findByTag('service') as $svc) {
$svc->handle();
}Reflection-free factories:
use Infocyph\InterMix\DI\Container;
use Infocyph\InterMix\DI\Support\LifetimeEnum;
$c->bindFactory(
Database::class,
static fn (Container $container): Database => new Database(
$container->get(DatabaseConfig::class),
),
LifetimeEnum::Singleton,
tags: ['infrastructure'],
);
// Equivalent fluent lifetime selection:
$c->factory(
RequestContext::class,
static fn (Container $container): RequestContext => new RequestContext(
$container->get('request.id'),
),
)->scoped();Use a regular closure definition when its parameters should be autowired. Use
bindFactory() or factory() when dependencies are explicit and request-time
reflection should be avoided. Direct factories behave identically whether
container injection is enabled or disabled.
See full container guide at: https://docs.infocyph.com/projects/intermix/di/overview.html
MacroTest::mix(new class {
public function hello($name) {
return "Hey, $name!";
}
});
echo (new MacroTest)->hello('Ali'); // Hey, Ali!use Infocyph\CacheLayer\Cache\Cache;
$pool = Cache::memory('intermix.definitions'); // or any PSR-6 pool
$c->definitions()->enableDefinitionCache($pool, generation: 'deployment-2026-08');
$report = $c->definitions()->warmDefinitionCache();Only null, scalar, and recursively safe array values are persisted. Runtime service objects remain in the container's in-memory lifetime store. CacheLayer 3.1 is recommended and integration-tested, but remains optional; any PSR-6 pool is supported. Cache failures fail open by default, and the optional generation isolates deployments without clearing the caller-owned pool.
use Infocyph\InterMix\DI\Support\FactoryDefinition;
use Infocyph\InterMix\DI\Support\ServiceReference;
$path = __DIR__ . '/var/intermix.compiled.php';
// Explicit recipes can be executed dynamically and compiled safely.
$c->bind('mailer', FactoryDefinition::construct(Mailer::class, [
new ServiceReference(Logger::class),
'transactional',
]));
// Build time, after every definition and option is registered.
$c->compileTo($path);
$report = $c->compilationReport();
// Runtime, after performing the same registration.
$c->useCompiled($path);Artifacts include PHP, InterMix, environment, definition, resolution
configuration, lifetime, tag, and compiled-recipe fingerprints. Incompatible
artifacts fail closed. Automatic class recipes pass conservative cache-time
eligibility checks; contextual, attributed, resource-configured, implicit-method,
and otherwise dynamic definitions remain on the normal resolver with an exact
reason in the compilation report. A later container configuration mutation
disables the active map until it is rebuilt. Ordinary closures and
bindFactory() definitions deliberately remain dynamic.
See the compiled resolver guide.
use Infocyph\InterMix\Serializer\ClosureSerializer;
$payload = ClosureSerializer::serialize(static fn (int $value): int => $value * 2);
$closure = ClosureSerializer::unserialize($payload);
$signed = ClosureSerializer::signed($_ENV['APP_KEY']);
$signedPayload = $signed->serialize(static fn (): string => 'queued work');
$signedClosure = $signed->unserialize($signedPayload);Ordinary PHP values use native PHP facilities. Resources remain the application's responsibility. Signing is instance-scoped and adds no work to normal invocation.
composer install
composer ic:testsDo not disclose suspected vulnerabilities in a public issue, discussion or pull request. Follow SECURITY.md and use GitHub private vulnerability reporting.
Intermix is protected by PHPForge, which provides automated tests, static and taint analysis, dependency auditing, architecture checks and release-readiness gates. Automated controls do not replace responsible disclosure or manual review.
MIT Licensed
Documentation • Security • Code of Conduct • Contributing
🗂️ Bug • Feature • Documentation • Question • CI failure
🔀 General • Bug fix • Feature • Refactor • Performance • Security & reliability • Documentation • Maintenance