1. Go to this page and download the library: Download x3p0-dev/x3p0-framework library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
x3p0-dev / x3p0-framework example snippets
namespace Your\Project;
interface Cache {}
final class FileCache implements Cache {}
final class ReportBuilder
{
// The container injects a Cache implementation automatically.
public function __construct(private readonly Cache $cache) {}
}
namespace Your\Project;
use X3P0\Framework\Core\ServiceProvider;
final class CacheServiceProvider extends ServiceProvider
{
// Bind an interface to a concrete, shared across the request.
protected const SINGLETONS = [
Cache::class => FileCache::class
];
// Resolve `'cache'` to the same binding as `Cache::class`.
protected const ALIASES = [
'cache' => Cache::class
];
}
namespace Your\Project;
use X3P0\Framework\Core\Application;
final class Plugin extends Application
{
protected const PROVIDERS = [
CacheServiceProvider::class
];
}
namespace Your\Project;
use X3P0\Framework\Container\ServiceContainer;
new Plugin(new ServiceContainer());
}
add_action('plugins_loaded', static function (): void {
do_action('your/project/register', plugin());
plugin()->boot();
}, -999);
use X3P0\Framework\Core\ServiceProvider;
final class BlockServiceProvider extends ServiceProvider
{
// Shared instances. A bare value is self-bound (the class is its own
// concrete); a key => value pair binds an abstract to a concrete.
protected const SINGLETONS = [
BlockRegistry::class,
Renderer::class => HtmlRenderer::class
];
// New instance on every resolution. Same key conventions as SINGLETONS.
protected const TRANSIENTS = [
RequestContext::class
];
// Overridable defaults: registered only if the abstract isn't already
// bound, so an extension can replace them regardless of load order.
protected const SINGLETONS_IF = [
Logger::class => NullLogger::class
];
protected const TRANSIENTS_IF = [
View::class => PhpView::class
];
// Alias => abstract. Resolving the alias resolves the abstract.
protected const ALIASES = [
'blocks' => BlockRegistry::class
];
// Tag => list of abstracts, resolvable together via `tagged()`.
protected const TAGS = [
'theme.blocks' => [AlertBlock::class, CalloutBlock::class]
];
// Services resolved and booted during the provider's boot phase. Each
// must implement `Bootable`. They boot in the order listed.
protected const BOOTABLE = [
BlockRegistrar::class
];
}
public function register(): void
{
$this->container->singleton(Connection::class, function (Container $c): Connection {
return new Connection($c->get(Config::class)->dsn());
});
}
public function boot(): void
{
add_action('init', $this->registerBlocks(...));
}
use X3P0\Framework\Container\Container;
use X3P0\Framework\Core\ServiceProvider;
final class ReportServiceProvider extends ServiceProvider
{
public function __construct(Container $container, private readonly Clock $clock)
{
parent::__construct($container);
}
}
// Shared instance, built once and reused.
$container->singleton(Cache::class, FileCache::class);
// New instance on every resolution.
$container->transient(RequestContext::class);
// A value the container stores and returns as-is (never built or autowired).
$container->instance('config', new Config([...]));
// Alias one identifier to another (followed transitively).
$container->alias('cache', Cache::class);
// Resolve by identifier.
$cache = $container->get(Cache::class);
// Resolve a class, optionally overriding constructor parameters by name.
$report = $container->make(ReportBuilder::class, ['format' => 'pdf']);
// Build a fresh, unshared instance even if the abstract is bound as a
// singleton. The shared instance is left untouched; only this abstract is
// built anew — its dependencies still resolve normally (shared stays shared).
$scratch = $container->build(Cache::class);
// Invoke a callable with its parameters resolved from the container.
$result = $container->call([$controller, 'handle']);
$result = $container->call(SomeController::class . '::handle');
// Get a closure that resolves the service on each call — without the
// consumer needing the container itself.
$makeReport = $container->defer(ReportBuilder::class);
$report = $makeReport();
final class ReportBuilder
{
public function __construct(
private readonly Cache $cache, // resolved by type
private readonly int $limit = 50, // default used if not provided
) {}
}
$container->make(ReportBuilder::class);
use X3P0\Framework\Container\Attributes\Singleton;
#[Singleton]
final class FileCache implements Cache {}
use X3P0\Framework\Container\Attributes\SingletonWhen;
#[SingletonWhen([FeatureFlags::class, 'cacheIsShared'])]
final class FileCache implements Cache {}
use X3P0\Framework\Container\Attributes\Get;
use X3P0\Framework\Container\Attributes\Make;
use X3P0\Framework\Container\Attributes\Defer;
use X3P0\Framework\Container\Attributes\Tagged;
use X3P0\Framework\Container\Attributes\DeferTagged;
use X3P0\Framework\Container\Attributes\Build;
use X3P0\Framework\Container\Attributes\Param;
use X3P0\Framework\Container\Attributes\NoAutowire;
final class Dashboard
{
public function __construct(
// Resolve a specific identifier (a keyed binding or a chosen concrete).
#[Get('config')] private readonly Config $config,
// Resolve an identifier with inline constructor overrides, still
// honoring a matching cached singleton when none are given.
#[Make(ReportBuilder::class, ['format' => 'pdf'])] private readonly ReportBuilder $reportBuilder,
// Inject a closure that resolves the service lazily, on demand.
#[Defer(ReportBuilder::class)] private readonly Closure $makeReport,
// Inject every service assigned to a tag, already resolved.
#[Tagged('theme.blocks')] private readonly iterable $blocks,
// Inject the tagged services as deferred resolvers, keyed by class,
// so you build only the ones you actually use.
#[DeferTagged('report.sections')] private readonly array $sections,
// Build a fresh, unshared instance with inline constructor
// overrides — a private copy configured right here.
#[Build(TransientCache::class, ['ttl' => 3600])] private readonly Cache $cache,
// Resolve a container-backed named parameter set via `setParam()`.
#[Param('timezone')] private readonly string $timezone,
// Skip autowiring so the parameter keeps its default instead of the
// container building the type — here, leaving `$user` null rather
// than constructing a WP_User.
#[NoAutowire] private readonly ?WP_User $user = null
) {}
}
use X3P0\Framework\Container\Attributes\ContextualAttribute;
use X3P0\Framework\Container\Container;
#[Attribute(Attribute::TARGET_PARAMETER)]
final class CurrentUser implements ContextualAttribute
{
public function resolve(Container $container): object
{
return $container->get(UserRepository::class)->current();
}
}
use X3P0\Framework\Container\Attributes\Param;
final class ReportBuilder
{
public function __construct(
#[Param('timezone')] private readonly string $timezone
) {}
}
$container->tag([AlertBlock::class, CalloutBlock::class], 'theme.blocks');
foreach ($container->tagged('theme.blocks') as $block) {
$block->register();
}
add_action('your/project/register', static function ($app): void {
$app->container()->singleton(TestimonialBlock::class);
$app->container()->tag(TestimonialBlock::class, 'theme.blocks');
});
use X3P0\Framework\Container\Attributes\Tag;
#[Tag('channels', ['slug' => 'email'])]
final class EmailChannel implements Channel {}
$container->tagFromAttributes(EmailChannel::class);
// Run after the service is built, to mutate it in place. Runs once per build,
// so a singleton is observed only the first time it's created.
$container->resolving(ReportBuilder::class, function (object $builder, Container $c): void {
$builder->setTimezone($c->get(Config::class)->timezone());
});
// Wrap or replace the service with something honoring the same contract.
// Decorators stack in registration order. If the service is already
// resolved, the decorator is applied to the stored instance immediately.
$container->decorate(Cache::class, function (Cache $cache, Container $c): Cache {
return new LoggingCache($cache, $c->get(Logger::class));
});
$container->has(Cache::class); // resolvable? (bound or an autowirable class)
$container->registered(Cache::class); // explicitly bound or instance-registered?
$container->resolved(Cache::class); // already built and cached?
$container->forgetInstance(Cache::class); // drop the cached instance; rebuild next time
final class Plugin extends Application
{
protected const PROVIDERS = [
CoreServiceProvider::class,
AdminServiceProvider::class,
FrontendServiceProvider::class
];
}