Skip to content

Commit 026e242

Browse files
committed
Update docs
1 parent 94f36c2 commit 026e242

3 files changed

Lines changed: 507 additions & 145 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ A tiny, fully featured dependency injection container as a DSL.
88

99
## Table of contents
1010

11-
- [Contributing](CONTRIBUTING.md)
12-
- [Feature Guide](docs/README.md)
11+
- [Feature Guide](docs/README.md) - Full feature guide.
12+
- [INI DSL](docs/DSL.md) - Support for .ini files.
1313
- [Installation](docs/INSTALL.md)
14+
- [Contributing](CONTRIBUTING.md)
1415
- [License](LICENSE.md)
15-
- [What is a DSL?](docs/DSL.md)

docs/DSL.md

Lines changed: 285 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,289 @@
1-
# What is a DSL?
1+
# INI DSL Guide
22

3-
DSLs are Domain Specific Languages, small languages implemented for specific
4-
domains. Respect\Config is an **internal DSL** hosted on the INI format to
5-
hold dependency injection containers.
3+
Respect\Config extends the standard INI format with a DSL for declaring dependency
4+
injection containers. Everything in this guide maps to the PHP API described in the
5+
[Feature Guide](README.md) — if you haven't read that first, start there.
6+
7+
## Loading INI
8+
9+
```php
10+
use Respect\Config\IniLoader;
11+
12+
// From a file
13+
$container = IniLoader::load('services.ini');
14+
15+
// From a string
16+
$container = IniLoader::load('db_host = localhost');
17+
18+
// Onto an existing container
19+
IniLoader::load('overrides.ini', $container);
20+
```
21+
22+
## Simple Values
23+
24+
```ini
25+
app_name = "My Application"
26+
per_page = 20
27+
tax_rate = 0.075
28+
error_mode = PDO::ERRMODE_EXCEPTION
29+
severity = E_USER_ERROR
30+
```
31+
32+
```php
33+
$container->get('per_page'); // 20 (int)
34+
$container->get('tax_rate'); // 0.075 (float)
35+
$container->get('error_mode'); // 2 (PDO::ERRMODE_EXCEPTION)
36+
```
37+
38+
## Sequences
39+
40+
Comma-separated values inside brackets produce PHP arrays:
41+
42+
```ini
43+
allowed_origins = [http://localhost:8000, http://localhost:3000]
44+
```
45+
46+
```php
47+
// ['http://localhost:8000', 'http://localhost:3000']
48+
$container->get('allowed_origins');
49+
```
50+
51+
## Instances
52+
53+
Create instances using INI sections. The section name becomes the container key,
54+
the class name follows after a space:
55+
56+
```ini
57+
[connection PDO]
58+
dsn = "sqlite:app.db"
59+
```
60+
61+
An alternative inline syntax passes one value as the first constructor argument:
62+
63+
```ini
64+
connection PDO = "sqlite:app.db"
65+
```
66+
67+
Both yield the same result:
68+
69+
```php
70+
$container->get('connection'); // PDO instance
71+
```
72+
73+
The `instanceof` keyword uses the class name itself as the container key:
74+
75+
```ini
76+
[instanceof PDO]
77+
dsn = "sqlite:app.db"
78+
```
79+
80+
```php
81+
$container->get(PDO::class); // PDO instance, keyed by class name
82+
```
83+
84+
## Constructor Parameters
85+
86+
Parameter names under a section are matched to the class constructor via reflection:
87+
88+
```ini
89+
[connection PDO]
90+
dsn = "sqlite:app.db"
91+
username = "root"
92+
password = "secret"
93+
```
94+
95+
You can also pass all constructor arguments as a positional list:
96+
97+
```ini
98+
[connection PDO]
99+
__construct = ["sqlite:app.db", "root", "secret"]
100+
```
101+
102+
1. Set only the parameters you need — unset parameters keep their defaults.
103+
2. Trailing `null` parameters are automatically stripped so defaults apply.
104+
105+
## References
106+
107+
Use `[name]` as a parameter value to reference another container entry. This is
108+
the INI equivalent of passing an `Instantiator` object as a parameter in PHP:
109+
110+
Given the class:
111+
112+
```php
113+
class Mapper {
114+
public function __construct(public PDO $db) {}
115+
}
116+
```
117+
118+
Wire it with `[name]` references:
119+
120+
```ini
121+
[connection PDO]
122+
dsn = "sqlite:app.db"
123+
124+
[mapper Mapper]
125+
db = [connection]
126+
```
127+
128+
```php
129+
$container->get('mapper'); // Mapper instance with the PDO connection injected
130+
```
131+
132+
References also work inside sequences:
133+
134+
```ini
135+
admin = admin@example.com
136+
notify = [[admin], ops@example.com]
137+
```
138+
139+
```php
140+
$container->get('notify'); // ['admin@example.com', 'ops@example.com']
141+
```
142+
143+
## Method Calls
144+
145+
Call methods on an instance after construction using `[]` syntax.
146+
Each `methodName[]` entry is one call:
147+
148+
```ini
149+
[connection PDO]
150+
dsn = "sqlite:app.db"
151+
setAttribute[] = [PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION]
152+
setAttribute[] = [PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC]
153+
exec[] = "PRAGMA journal_mode=WAL"
154+
exec[] = "PRAGMA foreign_keys=ON"
155+
```
156+
157+
```php
158+
$container->get('connection'); // PDO with attributes set and PRAGMAs executed
159+
```
160+
161+
## Static Factory Methods
162+
163+
Static methods use the same `[]` syntax. They are detected automatically via
164+
reflection:
165+
166+
```ini
167+
[y2k DateTime]
168+
createFromFormat[] = [Y-m-d, 2000-01-01]
169+
```
170+
171+
```php
172+
$container->get('y2k'); // DateTime for 2000-01-01
173+
```
174+
175+
The `Container` will skip the constructor and use the factory, same as the pure
176+
PHP version.
177+
178+
## Properties
179+
180+
Names that don't match a constructor parameter or method are set as public
181+
properties on the instance:
182+
183+
```php
184+
class Request {
185+
public int $timeout = 10;
186+
public string $base_url = '';
187+
}
188+
```
189+
190+
```ini
191+
[request Request]
192+
timeout = 30
193+
base_url = "https://api.example.com"
194+
```
195+
196+
```php
197+
$container->get('request')->base_url; // 'https://api.example.com'
198+
```
199+
200+
The resolution order is: constructor parameter → static method → instance method → property.
201+
202+
## Autowiring
203+
204+
Use the `autowire` modifier to enable automatic type-hint resolution:
205+
206+
```php
207+
class UserRepository {
208+
public bool $cacheEnabled = false;
209+
public function __construct(public PDO $db) {}
210+
}
211+
```
212+
213+
```ini
214+
[connection PDO]
215+
dsn = "sqlite:app.db"
216+
217+
[repository autowire UserRepository]
218+
```
219+
220+
```php
221+
$container->get('repository'); // UserRepository with PDO auto-injected
222+
```
223+
224+
The `PDO` instance is injected automatically because the container has an
225+
entry keyed by `PDO`, matching the type hint on the constructor.
226+
227+
Explicit parameters can be mixed in alongside autowiring:
228+
229+
```ini
230+
[repository autowire UserRepository]
231+
cacheEnabled = true
232+
```
233+
234+
## Factory (Fresh Instances)
235+
236+
Use the `new` modifier to create a fresh instance on every access:
237+
238+
```php
239+
class PostController {
240+
public function __construct(public Mapper $mapper) {}
241+
}
242+
```
243+
244+
```ini
245+
[controller new PostController]
246+
mapper = [mapper]
247+
```
248+
249+
```php
250+
$a = $container->get('controller'); // new PostController
251+
$b = $container->get('controller'); // another new PostController
252+
assert($a !== $b);
253+
```
254+
Dependencies like `[mapper]` are still resolved and cached normally.
255+
256+
## String Interpolation
257+
258+
The `[name]` placeholder syntax can also be used inline within a string to
259+
build composite values. This always produces a string:
260+
261+
```ini
262+
db_driver = mysql
263+
db_host = localhost
264+
db_name = myapp
265+
db_dsn = "[db_driver]:host=[db_host];dbname=[db_name]"
266+
```
267+
268+
```php
269+
$container->get('db_dsn'); // "mysql:host=localhost;dbname=myapp"
270+
```
271+
272+
Only root-level simple scalars can be interpolated.
273+
274+
## State Precedence
275+
276+
When loading INI onto a pre-populated container, existing non-Instantiator
277+
values take precedence:
278+
279+
```php
280+
$container = new Container(['env' => 'production']);
281+
IniLoader::load('config.ini', $container);
282+
// If config.ini has env = development, the existing 'production' value wins
283+
```
284+
285+
This allows environment-specific values to be set before loading the INI file,
286+
ensuring they are not overwritten.
6287

7288
***
8289

0 commit comments

Comments
 (0)