Nette Documentation Preview

syntax
Passing Dependencies
********************

<div class=perex>

Arguments, or "dependencies" in DI terminology, can be passed to classes in the following main ways:

* passing by constructor
* passing by method (called a setter)
* by setting a property
* by method, annotation or attribute *inject*

</div>

The first three methods apply in general in all object-oriented languages, the fourth is specific to Nette presenters, so it is discussed in [separate chapter |/best-practices/inject-method-attribute]. We will now take a closer look at each of these options and show them with specific examples.


Constructor Injection
=====================

Dependencies are passed as arguments to the constructor when the object is created:

```php
class MyService
{
	/** @var Cache */
	private $cache;

	public function __construct(Cache $service)
	{
		$this->cache = $service;
	}
}

$service = new MyService($cache);
```

This form is useful for mandatory dependencies that the class absolutely needs to function, as without them the instance cannot be created.

Since PHP 8.0, we can use a shorter form of notation that is functionally equivalent:

```php
// PHP 8.0
class MyService
{
	public function __construct(
		private Cache $service,
	) {
	}
}
```

As of PHP 8.1, a property can be marked with a flag `readonly` that declares that the contents of the property will not change:

```php
// PHP 8.1
class MyService
{
	public function __construct(
		private readonly Cache $service,
	) {
	}
}
```

DI container passes dependencies to the constructor automatically using [autowiring]. Arguments that cannot be passed in this way (e.g. strings, numbers, booleans) [write in configuration |services#Arguments].


Setter Injection
================

Dependencies are passed by calling a method that stores them in a private properties. The usual naming convention for these methods is of the form `set*()`, which is why they are called setters.

```php
class MyService
{
	/** @var Cache */
	private $cache;

	public function setCache(Cache $service): void
	{
		$this->cache = $service;
	}
}

$service = new MyService;
$service->setCache($cache);
```

This method is useful for optional dependencies that are not necessary for the class function, since it is not guaranteed that the object will actually receive them (i.e., that the user will call the method).

At the same time, this method allows the setter to be called repeatedly to change the dependency. If this is not desirable, add a check to the method, or as of PHP 8.1, mark the property `$cache` with the `readonly` flag.

```php
class MyService
{
	/** @var Cache */
	private $cache;

	public function setCache(Cache $service): void
	{
		if ($this->cache) {
			throw new RuntimeException('The dependency has already been set');
		}
		$this->cache = $service;
	}
}
```

The setter call is defined in the DI container configuration in [section setup |services#Setup]. Also here the automatic passing of dependencies is used by autowiring:

```neon
services:
	-
		create: MyService
		setup:
			- setCache
```


Property Injection
==================

Dependencies are passed directly to the property:

```php
class MyService
{
	/** @var Cache */
	public $cache;
}

$service = new MyService;
$service->cache = $cache;
```

This method is considered inappropriate because the property must be declared as `public`. Hence, we have no control over whether the passed dependency will actually be of the specified type (this was true before PHP 7.4) and we lose the ability to react to the newly assigned dependency with our own code, for example to prevent subsequent changes. At the same time, the property becomes part of the public interface of the class, which may not be desirable.

The setting of the variable is defined in the DI container configuration in [section setup |services#Setup]:

```neon
services:
	-
		create: MyService
		setup:
			- $cache = @\Cache
```


Which Way to Choose?
====================

- constructor is suitable for mandatory dependencies that the class needs to function
- the setter, on the other hand, is suitable for optional dependencies, or dependencies that can be changed
- public variables are not recommended


{{composer: nette/di}}

Passing Dependencies

Arguments, or „dependencies“ in DI terminology, can be passed to classes in the following main ways:

  • passing by constructor
  • passing by method (called a setter)
  • by setting a property
  • by method, annotation or attribute inject

The first three methods apply in general in all object-oriented languages, the fourth is specific to Nette presenters, so it is discussed in separate chapter. We will now take a closer look at each of these options and show them with specific examples.

Constructor Injection

Dependencies are passed as arguments to the constructor when the object is created:

class MyService
{
	/** @var Cache */
	private $cache;

	public function __construct(Cache $service)
	{
		$this->cache = $service;
	}
}

$service = new MyService($cache);

This form is useful for mandatory dependencies that the class absolutely needs to function, as without them the instance cannot be created.

Since PHP 8.0, we can use a shorter form of notation that is functionally equivalent:

// PHP 8.0
class MyService
{
	public function __construct(
		private Cache $service,
	) {
	}
}

As of PHP 8.1, a property can be marked with a flag readonly that declares that the contents of the property will not change:

// PHP 8.1
class MyService
{
	public function __construct(
		private readonly Cache $service,
	) {
	}
}

DI container passes dependencies to the constructor automatically using autowiring. Arguments that cannot be passed in this way (e.g. strings, numbers, booleans) write in configuration.

Setter Injection

Dependencies are passed by calling a method that stores them in a private properties. The usual naming convention for these methods is of the form set*(), which is why they are called setters.

class MyService
{
	/** @var Cache */
	private $cache;

	public function setCache(Cache $service): void
	{
		$this->cache = $service;
	}
}

$service = new MyService;
$service->setCache($cache);

This method is useful for optional dependencies that are not necessary for the class function, since it is not guaranteed that the object will actually receive them (i.e., that the user will call the method).

At the same time, this method allows the setter to be called repeatedly to change the dependency. If this is not desirable, add a check to the method, or as of PHP 8.1, mark the property $cache with the readonly flag.

class MyService
{
	/** @var Cache */
	private $cache;

	public function setCache(Cache $service): void
	{
		if ($this->cache) {
			throw new RuntimeException('The dependency has already been set');
		}
		$this->cache = $service;
	}
}

The setter call is defined in the DI container configuration in section setup. Also here the automatic passing of dependencies is used by autowiring:

services:
	-
		create: MyService
		setup:
			- setCache

Property Injection

Dependencies are passed directly to the property:

class MyService
{
	/** @var Cache */
	public $cache;
}

$service = new MyService;
$service->cache = $cache;

This method is considered inappropriate because the property must be declared as public. Hence, we have no control over whether the passed dependency will actually be of the specified type (this was true before PHP 7.4) and we lose the ability to react to the newly assigned dependency with our own code, for example to prevent subsequent changes. At the same time, the property becomes part of the public interface of the class, which may not be desirable.

The setting of the variable is defined in the DI container configuration in section setup:

services:
	-
		create: MyService
		setup:
			- $cache = @\Cache

Which Way to Choose?

  • constructor is suitable for mandatory dependencies that the class needs to function
  • the setter, on the other hand, is suitable for optional dependencies, or dependencies that can be changed
  • public variables are not recommended