Skip to content

Commit 1caaebb

Browse files
committed
Add missing tests for the resolving callbacks on the container
+ bug fix related to multiple calls to "resolving" and "afterResolving" callbacks
1 parent d329797 commit 1caaebb

File tree

2 files changed

+392
-1
lines changed

2 files changed

+392
-1
lines changed

src/Illuminate/Container/Container.php

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ class Container implements ArrayAccess, ContainerContract
133133
*/
134134
protected $afterResolvingCallbacks = [];
135135

136+
/**
137+
* All the abstract keys which are bound with class names.
138+
*
139+
* @var array
140+
*/
141+
protected $boundToClassName = [];
142+
136143
/**
137144
* Define a contextual binding.
138145
*
@@ -222,6 +229,7 @@ public function isAlias($name)
222229
public function bind($abstract, $concrete = null, $shared = false)
223230
{
224231
$this->dropStaleInstances($abstract);
232+
$this->isConcreteClassName($abstract, $concrete);
225233

226234
// If no concrete type was given, we will simply set the concrete type to the
227235
// abstract type. After that, the concrete type to be registered as shared
@@ -674,7 +682,12 @@ protected function resolve($abstract, $parameters = [])
674682
$this->instances[$abstract] = $object;
675683
}
676684

677-
$this->fireResolvingCallbacks($abstract, $object);
685+
// To prevent extra call to resolving callbacks, we don't fire "resolving" callbacks
686+
// for interfaces bound with class path syntax, since the callback will be called
687+
// later, in a recursive call to make() when the bounded concrete is resolving.
688+
if (! $this->isAnInterfaceBoundedWithClassName($abstract)) {
689+
$this->fireResolvingCallbacks($abstract, $object);
690+
}
678691

679692
// Before returning, we will also set the resolved flag to "true" and pop off
680693
// the parameter overrides for this build. After those two things are done
@@ -1269,4 +1282,32 @@ public function __set($key, $value)
12691282
{
12701283
$this[$key] = $value;
12711284
}
1285+
1286+
/**
1287+
* Determine if the abstract is both an interface and is bounded to a class path (not a closure).
1288+
*
1289+
* @param string $abstract
1290+
* @return bool
1291+
*/
1292+
protected function isAnInterfaceBoundedWithClassName($abstract)
1293+
{
1294+
return interface_exists($abstract) && array_key_exists($abstract, $this->boundToClassName);
1295+
}
1296+
1297+
/**
1298+
* Detects whether the concrete param is a closure or a class path.
1299+
*
1300+
* @param string $abstract
1301+
* @param \Closure|string|null $concrete
1302+
* @return void
1303+
*/
1304+
protected function isConcreteClassName($abstract, $concrete)
1305+
{
1306+
if (! ($concrete instanceof Closure)) {
1307+
$this->boundToClassName[$abstract] = null;
1308+
} else {
1309+
// Needed when rebinding happens.
1310+
unset($this->boundToClassName[$abstract]);
1311+
}
1312+
}
12721313
}

0 commit comments

Comments
 (0)