-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from Peroxide-PHP/develop
Develop
- Loading branch information
Showing
11 changed files
with
464 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,128 @@ | ||
[eng](README.md) / [pt-br](README_PT.md) | ||
# Peroxide/Container | ||
|
||
A simple Dependency Injection container based on PSR-11 for APIs, with zero dependencies and low functionalities. | ||
A straightforward Dependency Injection container, designed for use with APIs, adhering to the PSR-11 standard. It boasts minimal functionality and operates independently, free from external dependencies. | ||
|
||
## Our filosophy | ||
We are passionate about working with components that are as clean and simple as possible. **Peroxide\Container** is a fusion of inspiration drawn from libraries such as *Laminas\ServiceManager*, *Pimple*, and with a touch of *PHPCI*. | ||
|
||
The great advantage is that we have no external dependencies. All configuration is achieved through PHP code using array configuration files. All you need to do is ensure that your framework supports PSR-11, set up the configuration, and you're ready to begin your coding journey. | ||
## How to use it | ||
### Instaling | ||
```bash | ||
composer require peroxide/container | ||
``` | ||
--- | ||
|
||
## Starting your journey | ||
**Peroxide\Container** is fully compliant with PSR-11, and it provides the following methods: | ||
|
||
```php | ||
# From PSR-11 | ||
public function get(string $id): object; | ||
public function has(string $id): bool; | ||
|
||
# From our interface SetDependency | ||
public function set(string $id, callable $factory): void; | ||
public function setInvokableClass(string $id, string $invocableClass): void; | ||
``` | ||
|
||
### Create you configuration as *array* | ||
```php | ||
<?php | ||
use Peroxide\DependencyInjection\Container; | ||
|
||
$config = [ | ||
YourDependencyName::class => fn() => new YourDependencyName(), | ||
YourDependency::class => YourDependencyFactoryClass::class, | ||
|
||
// should be invokable class | ||
ConcreteClass::class => new ConcreteClassFactory(), | ||
|
||
// Or passing as reference string | ||
ConcreteClass::class => ConcreteClassFactory::class | ||
]; | ||
|
||
$container = new Container($config); | ||
|
||
// how to get dependencies | ||
$container->get(YourDependencyName::class); | ||
$container->get(YourDependency::class); | ||
$container->get(ConcreteClass::class); | ||
``` | ||
### Creating your Factory Class | ||
```php | ||
use Psr\Container\ContainerInterface; | ||
use Peroxide\DependencyInjection\Interfaces\ContainerFactory; | ||
|
||
class ConcreteClassFactory implements ContainerFactory | ||
{ | ||
public function __invoke(ContainerInterface $container): ConcreteClass | ||
{ | ||
// config your dependency injection here | ||
// you can compose your dependency | ||
// return new ParentDependency($container->get(DependencyChild::class)); | ||
return new ConcreteClass(); | ||
} | ||
} | ||
``` | ||
It is also possible to set dependencies separately, after obtaining your container instance: | ||
```php | ||
use Peroxide\DependencyInjection\Container; | ||
|
||
$container = new Container(); | ||
|
||
$container->set(DependencyPath::class, fn() => new DependencyInstance()); | ||
``` | ||
|
||
If the dependency doesn't exist, it will be created; otherwise, it will be replaced by the new factory. | ||
## More configurations | ||
To handle dependency injection within the container, you can easily use ```arrow function``` to compose your dependencies. | ||
```php | ||
$container = new Container([ | ||
// Dependency parent with dependency child | ||
|
||
// all dependencies should be involved by a Closure(function() or fn()) | ||
Dependency::class => fn() => new Dependency(), | ||
|
||
ParentDependency::class => function($container) { | ||
return new ParentDependency( | ||
$container->get(Dependency::class) | ||
); | ||
} | ||
// or simply | ||
ParentDependency::class => fn($c) => new ParentDependency($c->get(Dependency::class)) | ||
]); | ||
``` | ||
You can also compose your configuration using the spread operator, as shown in the example: | ||
```php | ||
use Peroxide\DependencyInjection\Container; | ||
# on 'dependencies.php' config file | ||
$config1 = [ ... ]; | ||
$config2 = [ ... ]; | ||
return [...$config1, ...$config2]; | ||
|
||
// ------------------- | ||
|
||
$config = require __DIR__ . '/dependencies.php'; | ||
|
||
$container = new Container($config); | ||
``` | ||
## How to deal with Singleton? | ||
Just use the Singleton invocable class, here's an example: | ||
```php | ||
use Peroxide\DependencyInjection\Container; | ||
use Peroxide\DependencyInjection\Invokables\Singleton; | ||
|
||
$container = new Container([ | ||
// Dependency parent with dependency child | ||
Dependency::class => new Singleton(fn() => new Dependency()), | ||
ParentDependency::class => new Singleton( | ||
fn($container) => new ParentDependency($container->get(Dependency::class)) | ||
) | ||
]); | ||
``` | ||
The ```Peroxide\DependencyInjection\Invokables\Singleton``` class serves as a wrapper to indicate to our container that we want this class to not create a new instance every time it is retrieved. | ||
|
||
## Why can't I config parameters on container? | ||
We believe that storing configuration values in the dependency container is unnecessary. Instead, each service should be configured using external environment data. By doing so, you can centralize your project's configuration. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
[eng](README.md) / [pt-br](README_PT.md) | ||
# Peroxide/Container | ||
|
||
Um contêiner de Injeção de Dependência direto, projetado para ser usado com APIs, aderindo ao padrão PSR-11. Ele oferece funcionalidade mínima e opera de forma independente, sem depender de recursos externos. | ||
## Nossa filosofia | ||
Somos apaixonados por trabalhar com componentes o mais limpos e simples possível. **Peroxide/Container** é uma fusão de inspiração proveniente de bibliotecas como *Laminas\ServiceManager*, *Pimple*, e um toque de *PHPCI*. | ||
|
||
A grande vantagem é que não temos dependências externas. Toda a configuração é feita por meio de código PHP usando arquivos de configuração em forma de arrays. Tudo o que você precisa fazer é garantir que seu Framework suporte a PSR-11, configure a biblioteca e você estará pronto para começar sua jornada de codificação. | ||
|
||
## Como usar | ||
### Instalando | ||
```bash | ||
composer require peroxide/container | ||
``` | ||
--- | ||
|
||
## Iniciando sua jornada | ||
**Peroxide\Container** está totalmente em conformidade com a PSR-11 e oferece os seguintes métodos: | ||
|
||
```php | ||
# From PSR-11 | ||
public function get(string $id): object; | ||
public function has(string $id): bool; | ||
|
||
# From our interface SetDependency | ||
public function set(string $id, callable $factory): void; | ||
public function setInvokableClass(string $id, string $invocableClass): void; | ||
``` | ||
|
||
### Crie sua configuração com arrays | ||
```php | ||
<?php | ||
use Peroxide\DependencyInjection\Container; | ||
|
||
$config = [ | ||
YourDependencyName::class => fn() => new YourDependencyName(), | ||
YourDependency::class => YourDependencyFactoryClass::class, | ||
|
||
// deve ser uma classe invocável | ||
ConcreteClass::class => new ConcreteClassFactory(), | ||
|
||
// Ou passe como uma referencia em string seu factory | ||
ConcreteClass::class => ConcreteClassFactory::class | ||
]; | ||
|
||
$container = new Container($config); | ||
|
||
// como resgatar sua dependência pronta | ||
$container->get(YourDependencyName::class); | ||
$container->get(YourDependency::class); | ||
$container->get(ConcreteClass::class); | ||
``` | ||
### Criando sua classe Factory | ||
```php | ||
use Psr\Container\ContainerInterface; | ||
use Peroxide\DependencyInjection\Interfaces\ContainerFactory; | ||
|
||
class ConcreteClassFactory implements ContainerFactory | ||
{ | ||
public function __invoke(ContainerInterface $container): ConcreteClass | ||
{ | ||
// configure sua injeção de dependência aqui | ||
// você pode compor sua dependência | ||
// retorne new ParentDependency($container->get(DependencyChild::class)); | ||
return new ConcreteClass(); | ||
} | ||
} | ||
``` | ||
Também é possível definir dependências separadamente, após obter a instância do seu contêiner: | ||
```php | ||
use Peroxide\DependencyInjection\Container; | ||
|
||
$container = new Container(); | ||
|
||
$container->set(DependencyPath::class, fn() => new DependencyInstance()); | ||
``` | ||
|
||
Se a dependência não existir, ela será criada; caso contrário, será substituída pela atual definição. | ||
## Mais configurações | ||
Para lidar com injeção de dependência dentro do contêiner, você pode facilmente usar uma ```arrow function``` para compor suas dependências. | ||
```php | ||
$container = new Container([ | ||
// todas as dependências devem ser envolvidas por uma Closure (função ou fn()) | ||
Dependency::class => fn() => new Dependency(), | ||
|
||
ParentDependency::class => function($container) { | ||
return new ParentDependency( | ||
$container->get(Dependency::class) | ||
); | ||
} | ||
// ou simplesmente | ||
ParentDependency::class => fn($c) => new ParentDependency($c->get(Dependency::class)) | ||
]); | ||
``` | ||
Você também pode compor sua configuração usando o operador de expansão, como mostrado no exemplo: | ||
```php | ||
use Peroxide\DependencyInjection\Container; | ||
# no arquivo de configuração 'dependencies.php' | ||
$config1 = [ ... ]; | ||
$config2 = [ ... ]; | ||
return [...$config1, ...$config2]; | ||
|
||
// ------------------- | ||
# em index.php | ||
$config = require __DIR__ . '/dependencies.php'; | ||
|
||
$container = new Container($config); | ||
``` | ||
## Como lidar com Singleton? | ||
Basta usar a classe ```Singleton```, aqui está um exemplo: | ||
```php | ||
use Peroxide\DependencyInjection\Container; | ||
use Peroxide\DependencyInjection\Invokables\Singleton; | ||
|
||
$container = new Container([ | ||
// Dependência pai com dependência filha | ||
Dependency::class => new Singleton(fn() => new Dependency()), | ||
ParentDependency::class => new Singleton( | ||
fn($container) => new ParentDependency($container->get(Dependency::class)) | ||
) | ||
]); | ||
``` | ||
A classe ```Peroxide\DependencyInjection\Invokables\Singleton``` atua como um invólucro para indicar ao nosso contêiner que desejamos que esta classe não crie uma nova instância toda vez que for solicitada. | ||
|
||
## Por que não posso configurar parâmetros no contêiner? | ||
Acreditamos que não é necessário armazenar valores de configuração no contêiner de dependência. Em vez disso, cada serviço deve ser configurado usando dados de ambiente externos (por exemplo .env). Fazendo isso, você centraliza a configuração do seu projeto. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?php | ||
|
||
namespace Peroxide\DependencyInjection\Invokables; | ||
|
||
use Peroxide\DependencyInjection\Interfaces\ContainerFactory; | ||
use Psr\Container\ContainerInterface; | ||
|
||
use Closure; | ||
|
||
class Singleton implements ContainerFactory | ||
{ | ||
/** | ||
* @var array<string, object> | ||
*/ | ||
protected array $singletonObjects = []; | ||
|
||
/** | ||
* @var Closure $factoryAction | ||
*/ | ||
protected Closure $factoryAction; | ||
|
||
public function __construct( | ||
callable $factory, | ||
protected string $dependencyId = '' | ||
) { | ||
$this->dependencyId = uniqid(); | ||
$this->factoryAction = $factory; | ||
} | ||
|
||
public function has(string $dependencyId): bool | ||
{ | ||
return isset($this->singletonObjects[$dependencyId]); | ||
} | ||
|
||
protected function store(string $dependencyName, callable $factoryAction, ContainerInterface $container): void | ||
{ | ||
$this->singletonObjects[$dependencyName] = $factoryAction($container); | ||
} | ||
|
||
public function __invoke(ContainerInterface $container): object | ||
{ | ||
if ($this->has($this->dependencyId)) { | ||
return $this->singletonObjects[$this->dependencyId]; | ||
} | ||
$this->store($this->dependencyId, $this->factoryAction, $container); | ||
return $this->singletonObjects[$this->dependencyId]; | ||
} | ||
} |
Oops, something went wrong.