Skip to content

Commit 84e1217

Browse files
init
0 parents  commit 84e1217

9 files changed

Lines changed: 647 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
.phpunit.result.cache

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# HackPHP Container
2+
HackPHP dependency injection container.
3+
4+
## Installation
5+
```sh
6+
composer require hackphp/container
7+
```
8+
9+
## Usage
10+
```php
11+
12+
use Hackphp\Container\Container;
13+
14+
$container = Container::getInstance();
15+
16+
// bind class to the container by key = class name
17+
$container->bind(ApiHandler::class, fn () => new ApiHandler("123"));
18+
19+
// bind by key = interface.
20+
$conainer->bind(ApiInterface::class, TestApi::class);
21+
22+
// bind by key = string
23+
$container->bind("api", fn () => new Api);
24+
25+
// bind singleton
26+
$container->singleton(ApiInterface::class, fn () => new ApiHandler("123"));
27+
28+
// bind class without instructuions
29+
$container->bind(TestApi::class);
30+
$container->singleton(TestApi::class);
31+
32+
// pass the object instead of closure or string
33+
$apiHandler = new ApiHandler("123");
34+
$container->instance(ApiInterface::class, $apiHandler);
35+
36+
// resolve binding
37+
$container->make("api"); // use string key
38+
$container->make(ApiInterface::class);
39+
40+
// PSR-11
41+
$container->get("api");
42+
$container->has("api") // bool
43+
```

composer.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "hackphp/container",
3+
"description": "HackPHP PSR-11 compatible container",
4+
"type": "library",
5+
"authors": [
6+
{
7+
"name": "Mohamed Samir",
8+
"email": "gm.mohamedsamir@gmail.com"
9+
}
10+
],
11+
"require": {
12+
"psr/container": "2.0.x-dev"
13+
},
14+
"require-dev": {
15+
"phpunit/phpunit": "9.5.x-dev"
16+
},
17+
"license": "MIT",
18+
"autoload": {
19+
"psr-4": {
20+
"Hackphp\\Container\\": "src/"
21+
}
22+
},
23+
"autoload-dev": {
24+
"psr-4": {
25+
"Hackphp\\Tests\\Container\\": "tests/"
26+
}
27+
},
28+
"minimum-stability": "dev",
29+
"scripts": {
30+
"test": "./vendor/bin/phpunit --do-not-cache-result"
31+
}
32+
}

phpunit.xml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<phpunit
4+
bootstrap = "vendor/autoload.php"
5+
backupGlobals = "false"
6+
backupStaticAttributes = "false"
7+
colors = "true"
8+
convertErrorsToExceptions = "true"
9+
convertNoticesToExceptions = "true"
10+
convertWarningsToExceptions = "true"
11+
processIsolation = "false"
12+
stopOnFailure = "false">
13+
14+
<testsuites>
15+
<testsuite name="Test Suite">
16+
<directory>tests</directory>
17+
</testsuite>
18+
</testsuites>
19+
20+
<php>
21+
<env name="APP_ENV" value="testing"/>
22+
</php>
23+
24+
</phpunit>

src/Autowire.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
namespace Hackphp\Container;
4+
5+
use ReflectionClass;
6+
use ReflectionNamedType;
7+
8+
class Autowire
9+
{
10+
/**
11+
* @var ReflectionClass
12+
*/
13+
private ReflectionClass $class;
14+
15+
/**
16+
* Create new Autowire.
17+
*
18+
* @param string $className
19+
*/
20+
public function __construct($className)
21+
{
22+
$this->class = new ReflectionClass($className);
23+
}
24+
25+
/**
26+
* Check if the class constructor has the given paramter.
27+
*
28+
* @param string $paramName
29+
* @return bool
30+
*/
31+
public function constructHasType($typeName): bool
32+
{
33+
$constructor = $this->class->getConstructor();
34+
35+
if (is_null($constructor)) {
36+
return false;
37+
}
38+
39+
foreach ($constructor->getParameters() as $param) {
40+
$type = $param->getType();
41+
42+
if (!$type instanceof ReflectionNamedType) {
43+
continue;
44+
}
45+
46+
if ($typeName == $type->getName()) {
47+
return true;
48+
}
49+
}
50+
51+
return false;
52+
}
53+
}

src/Container.php

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
3+
namespace Hackphp\Container;
4+
5+
use Closure;
6+
use Psr\Container\ContainerInterface;
7+
8+
class Container implements ContainerInterface
9+
{
10+
use Resolver;
11+
12+
/**
13+
* Container instance.
14+
*
15+
* @var static
16+
*/
17+
protected static $instance;
18+
19+
/**
20+
* The binded services.
21+
*
22+
* @var array
23+
*/
24+
protected array $bindings = [];
25+
26+
/**
27+
* The shared services.
28+
*
29+
* @var array
30+
*/
31+
protected array $instances = [];
32+
33+
/**
34+
* Enable/Disable autowiring.
35+
*
36+
* @var bool
37+
*/
38+
protected bool $autowiring = true;
39+
40+
/**
41+
* Prevent create new instance.
42+
*/
43+
private function __construct()
44+
{
45+
}
46+
47+
/**
48+
* Get the Container instance.
49+
*
50+
* @return static
51+
*/
52+
public static function getInstance(): self
53+
{
54+
if (is_null(static::$instance)) {
55+
static::$instance = new static();
56+
}
57+
58+
return static::$instance;
59+
}
60+
61+
/**
62+
* @inheritDoc
63+
*/
64+
public function get(string $id)
65+
{
66+
return $this->make($id);
67+
}
68+
69+
/**
70+
* @inheritDoc
71+
*/
72+
public function has(string $id): bool
73+
{
74+
return isset($this->bindings[$id]) || isset($this->instances[$id]);
75+
}
76+
77+
/**
78+
* Bind entry to the container.
79+
*
80+
* @param string $name
81+
* @param Closure|string|null $entry
82+
* @param bool $shared
83+
* @return void
84+
*/
85+
public function bind(string $name, $entry = null, bool $shared = false): void
86+
{
87+
$this->bindings[$name] = [
88+
"entry" => $entry,
89+
"shared" => $shared
90+
];
91+
}
92+
93+
/**
94+
* Buind entry to the container as singleton.
95+
*
96+
* @param string $name
97+
* @param Closure|string|null $entry
98+
* @return void
99+
*/
100+
public function singleton(string $name, $entry = null): void
101+
{
102+
$this->bind($name, $entry, true);
103+
}
104+
105+
/**
106+
* Bind entry to the container shared instances.
107+
*
108+
* @param string $name
109+
* @param mixed $entry
110+
* @return void
111+
*/
112+
public function instance(string $name, $entry): void
113+
{
114+
$this->instances[$name] = $entry;
115+
}
116+
117+
/**
118+
* Get the entry from the container.
119+
*
120+
* @param string $name
121+
* @return mixed
122+
*/
123+
public function make(string $name)
124+
{
125+
return $this->resolve($name);
126+
}
127+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Hackphp\Container\Exceptions;
4+
5+
use Exception;
6+
7+
class BindingException extends Exception
8+
{
9+
}

0 commit comments

Comments
 (0)