laminas / laminas-di Goto Github PK
View Code? Open in Web Editor NEWAutomated dependency injection for PSR-11 containers
Home Page: https://docs.laminas.dev/laminas-di/
License: BSD 3-Clause "New" or "Revised" License
Automated dependency injection for PSR-11 containers
Home Page: https://docs.laminas.dev/laminas-di/
License: BSD 3-Clause "New" or "Revised" License
From PR #35
ZF is aiming to allow easy migrations to new component versions whenever possible. For zend-di there is a component that integrated version 2 into zend-servicemanager.
Version 3 introduced a conflict-entry in it's composer.json, that states clearly zend-servicemanager-di is no longer needed. But it will also urge consumers to potentially upgrade many parts of their application.
To make life easier for these users, we should provide a new version for zend-servicemanager-di, that will deprecate it's own usage but allowing the user's to remove it's parts step by step.
This issue should keep track of this topic after migration to Laminas is complete.
Originally posted by @tux-rampage at zendframework/zend-di#58
There are a lot of new conventions that are not covered by the current phpcs ruleset of zend-coding-standard (v1.x).
Some examples are (incomplete list):
!
)A new coding style and tooling is currently work in progress at zendframework/zend-coding-standard#5. When this PR is merged and v2 is released this zend-di should integrate it.
Depending on my availability, I'll perform the tests as suggested in the mentioned PR.
Originally posted by @tux-rampage at zendframework/zend-di#39
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These problems occurred while renovating this repository. View logs.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
composer.json
php ~8.1.0 || ~8.2.0 || ~8.3.0
laminas/laminas-stdlib ^3.18.0
psr/container ^1.1.1
psr/log ^1.1.4 || ^2.0.0 || ^3.0.0
laminas/laminas-coding-standard ~2.5.0
laminas/laminas-servicemanager ^3.22
mikey179/vfsstream ^1.6.11@alpha
phpbench/phpbench ^1.2.7
phpunit/phpunit ^9.5.26
psalm/plugin-phpunit ^0.18.0
squizlabs/php_codesniffer ^3.7.1
vimeo/psalm ^5.0
.github/workflows/continuous-integration.yml
.github/workflows/docs-build.yml
.github/workflows/release-on-milestone-closed.yml
Installing on Symfony 6.2 project with PHP 8.1
Q | A |
---|---|
Version(s) | 3.0.6 |
Get this Exception :
PHP Fatal error: Declaration of Laminas......::has($name) must be compatible with Psr\Container\ContainerInterface::has(string $id): bool in /path/info line int
Same as described here: #78
Solution: replace laminas/laminas-crypt:^3.4 by laminas/laminas-crypt:^3.10 where bug has been fixed.
Q | A |
---|---|
Proposed Version(s) | 4.0.0 |
BC Break? | Yes |
Provide users an option to add the AoT compiler as a dev dependency
At the Moment the AoT compiler is part of this package, but it should not be a requirement for running the application.
Therefore the AoT compiler should be extracted and provided in a separate package and all AoT-only code should be stripped from this repo.
The existing AoT compiler should be deprecated and Facaded within the AoT Package to provide a migration path without breaking at the first update.
suggest
entry.Q | A |
---|---|
Version(s) | 3.7.x |
When trying to create an object that depends on a union type in its constructor, a call to Injector::create()
results in an error.
The Injector::class
forwards the resolveParameters()
call to the DependencyResolver::resolveParameters()
method, which, at L#280 makes a call to Parameter::getType(). Within this method, a call is made to the underlying object's ReflectionParameter::getType()
method is made. The returned object by getType()
is a ReflectionUnionType::class, which has no method getName()
defined, and hence, it crashes the program due to L#63.
The error message:
Error: Call to undefined method ReflectionUnionType::getName()
Settings:
PHP 8.0.19 (cli)
Class definition:
class Foo
{
public function __construct(private string|Stringable $s)
{
}
public function getS(): string|Stringable
{
return $this->s;
}
}
Test case:
public function testCreateClassWithUnionTypeParameterAsConstructorArgument(): void
{
$injector = new Injector();
$s = 'Hello, World';
$foo = $injector->create(Foo::class, ['s' => $s]);
$actualS = $foo->getS();
$this->assertEquals($s, $actualS);
}
An instance of Foo::class
constructed with the property $s
set to the string value 'Hello, World'
.
I am sorry if this is not considered a bug, but I did not know where to otherwise post this matter. Please let me know what you think of the above stated.
Q | A |
---|---|
Proposed Version(s) | 3.4.0 |
BC Break? | ? |
Reduce the maintenance Overhead and runtime cost when deprecating elements.
Since static analysis tools like psalm have become quite powerful to analyse the code before it gets executed.
Therefore we should drop every trigger_error
of a E_USER_DEPRECATED
where a deprecation is already caught by static analysis. We should only keep it, where static analysis tool cannot catch then (for example when config keys have changed).
Another extreme weakness of deprecation notices during runtime is, that they only occur when the code path is actually executed. This means deprecated elements may be still in use undiscovered for a long time until somebody hits the execution path by accident.
Runtime deprecations are also a horror to maintain and they usually require ugly work arounds to be added like in https://github.com/laminas/laminas-di/blob/3.4.x/phpcs.xml#L21
Some library consumers may not use static analysis to validate their code which are then cut of from being noted about deprecations.
This is a sign of poor code quality and tech debt. We should encourage users to use static analysis instead relying on runtime behaviour.
trigger_error
statements from the codebase where a deprecation annotation is used@deprecated
Doc-Block annotations (usually those are already present)@see
to point to an alternative or a migration guide for the userRunning laminas-servicemanager-di test suite
PHP Fatal error: Declaration of Laminas\Di\Di::has($name) must be compatible with Psr\Container\ContainerInterface::has(string $id): bool in /usr/share/php/Laminas/Di/Di.php on line 220
Q | A |
---|---|
New Feature | yes |
To be prepared for the december release of PHP 8.0, this repository has some additional TODOs to be tested against the new major version.
In order to make this repository compatible, one has to follow these steps:
composer.json
to provide support for PHP 8.0 by adding the constraint ~8.0.0
composer.json
to drop support for PHP less than 7.3composer.json
to implement phpunit 9.3 which supports PHP 7.3+.travis.yml
to ignore platform requirements when installing composer dependencies (simply add --ignore-platform-reqs
to COMPOSER_ARGS
env variable).travis.yml
to add PHP 8.0 to the matrix (NOTE: Do not allow failures as PHP 8.0 has a feature freeze since 2020-08-04!)Q | A |
---|---|
QA | yes |
As decided during the Technical-Steering-Committee Meeting on August 3rd, 2020, Laminas wants to implement vimeo/psalm in all packages.
Implementing psalm is quite easy.
psalm.xml
in the project root$ composer require --dev vimeo/psalm
$ vendor/bin/psalm --set-baseline=psalm-baseline.xml
static-analysis
with the command psalm --shepherd --stats
script:
in .travis.yml
: - if [[ $TEST_COVERAGE == 'true' ]]; then composer static-analysis ; fi
phpstan.neon.dist
, .travis.yml
entry, composer.json
require-dev
and scripts
)Different versions can be handled by our documentation theme.
laminas-hydrator use different versions in documentation already:
https://github.com/laminas/laminas-hydrator/blob/02a5cfdc0dbf2b9abbe7aca3472de514d10e2d6b/mkdocs.yml#L6-L27
In order to improve AoT compiler, on my project I've done some changes.
The problem is that with AoT, dependency factories are not created. To accomplish my goal I've made a simple DependencyScanner that try to fetch every dependency classes:
<?php
declare(strict_types=1);
namespace AppAoT\Scanner;
use Zend\Code\Reflection\ClassReflection;
class DependencyScanner
{
/** @var string[] */
private $classNamesToScan;
/** @var string[] */
private $classNames = [];
/** @var bool */
private $isScanned = false;
/**
* DependencyScanner constructor.
*
* @param string[] $classNamesToScan
*/
public function __construct(array $classNamesToScan = [])
{
$this->classNamesToScan = $classNamesToScan;
}
protected function scan(): void
{
if ($this->isScanned) {
return;
}
foreach ($this->classNamesToScan as $className)
{
$this->scanClass($className);
}
$this->isScanned = true;
}
protected function scanClass(string $name): void
{
if (! \class_exists($name)) {
return;
}
if (\array_key_exists($name, $this->classNames)) {
return;
}
$this->classNames[$name] = true;
$classReflection = new ClassReflection($name);
$constructor = $classReflection->getConstructor();
if (null === $constructor) {
return;
}
$parameters = $constructor->getParameters();
foreach ($parameters as $parameter) {
$class = $parameter->getClass();
if (null === $class) {
continue;
}
$this->scanClass($class->getName());
}
}
/**
* @return string[]
*/
public function getClassNames(): array
{
$this->scan();
return \array_keys($this->classNames);
}
}
And changed my di-generate-aot.sh
to use it, getting every psr-4
namespace directory (does not support dir arrays yet), and using the previous class to fetch every dependency class.
<?php
namespace AppAoT;
use AppAoT\Scanner\DependencyScanner;
use Psr\Container\ContainerInterface;
use Zend\Code\Scanner\DirectoryScanner;
use Zend\Di\CodeGenerator\InjectorGenerator;
use Zend\Di\ConfigInterface;
use Zend\Di\Definition\RuntimeDefinition;
use Zend\Di\Resolver\DependencyResolver;
require __DIR__ . '/../vendor/autoload.php';
$composerFile = __DIR__ . '/../composer.json';
if (! \is_readable($composerFile)) {
throw new \RuntimeException('Unable to find composer.json');
}
$composer = \json_decode(\file_get_contents($composerFile), true);
$directories = \array_values($composer['autoload']['psr-4'] ?? []);
/** @var ContainerInterface $container */
$container = require __DIR__ . '/../config/container.php';
$config = $container->get(ConfigInterface::class);
$resolver = new DependencyResolver(new RuntimeDefinition(), $config);
$resolver->setContainer($container);
$scanner = new DirectoryScanner($directories);
$dependencyScanner = new DependencyScanner($scanner->getClassNames());
$classNames = $dependencyScanner->getClassNames();
$generator = new InjectorGenerator($config, $resolver, __NAMESPACE__ . '\Generated');
$generator->setOutputDirectory(__DIR__ . '/../src/AppAoT/gen');
$generator->generate($classNames);
It's just an example, but I think we can include something like that in zend-code
and/or here, and improve the documentation in order to provide a better AoT compiler compared to others compiled containers.
P.S. It does not resolve aliases yet.
Originally posted by @thomasvargiu at zendframework/zend-di#42
Can we add support for Psr LoggerInterface to v2 and v3 ("psr/log": "^1.0|^2.0|^3.0"
) ?
Currently, only v1.1.4 is supported :
Line 38 in b9a5357
It seems methods of Test-Classes should have return types, this is not the case within this project.
The TODO would be to add these return types.
Originally posted by @tux-rampage at zendframework/zend-di#40
I think the documentation is wrong:
https://docs.zendframework.com/zend-di/cookbook/aot-guide/#5-add-aot-to-the-service-manager
In getDependencies
method of ConfigProvider
we have:
'factories' => $this->getGeneratedFactories(),
'delegators' => [
InjectorInterface::class => [
InjectorDecoratorFactory::class,
],
],
but I think one of this configuration is useless.
If we inject generated factories in factories
key then we don't need to use decorator (which uses GeneratedInjector and in fact is an abstract factory - but uses only generated factories list).
But in case we have factories injected already into service manager the abstract factory for the service is not going to be called as the factory is defined. If the factory is not defined (so for example service was added later and factories were not regenerated) then normal injector is going to be used anyway (generated injector is just the proxy to origin injector in case factory is not defined).
Of course it doesn't change too much, but in case we need use injector (abstract factory) we don't need to check again on generated list, as this is not there.
Originally posted by @michalbundyra at zendframework/zend-di#53
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.