Skip to content

Commit 1df63e6

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 1df63e6

File tree

2 files changed

+390
-1
lines changed

2 files changed

+390
-1
lines changed

src/Illuminate/Container/Container.php

Lines changed: 40 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->decideAboutConcreteType($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,11 @@ protected function resolve($abstract, $parameters = [])
674682
$this->instances[$abstract] = $object;
675683
}
676684

677-
$this->fireResolvingCallbacks($abstract, $object);
685+
// We don't fire "resolving" callbacks for interface bound with class path syntax
686+
// since the callback will fire later, when the bounded concrete is resolving.
687+
if (! $this->isAnInterfaceBoundedWithClassName($abstract)) {
688+
$this->fireResolvingCallbacks($abstract, $object);
689+
}
678690

679691
// Before returning, we will also set the resolved flag to "true" and pop off
680692
// the parameter overrides for this build. After those two things are done
@@ -1269,4 +1281,31 @@ public function __set($key, $value)
12691281
{
12701282
$this[$key] = $value;
12711283
}
1284+
1285+
/**
1286+
* Determine if the abstract is both an interface and is bounded to a class path (not a closure).
1287+
*
1288+
* @param string $abstract
1289+
* @return bool
1290+
*/
1291+
protected function isAnInterfaceBoundedWithClassName($abstract)
1292+
{
1293+
return interface_exists($abstract) && array_key_exists($abstract, $this->boundToClassName);
1294+
}
1295+
1296+
/**
1297+
* Detects what type of concrete is provided for the abstract.
1298+
*
1299+
* @param string $abstract
1300+
* @param \Closure|string|null $concrete
1301+
* @return void
1302+
*/
1303+
protected function decideAboutConcreteType($abstract, $concrete)
1304+
{
1305+
if ($concrete instanceof Closure) {
1306+
unset($this->boundToClassName[$abstract]);
1307+
} else {
1308+
$this->boundToClassName[$abstract] = null;
1309+
}
1310+
}
12721311
}

0 commit comments

Comments
 (0)