Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add make() method #11

Merged
merged 3 commits into from
Jun 20, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,14 @@ public function unset(string $id): void
/**
* {@inheritDoc}
*/
public function make(string $concrete)
public function make(string $concrete, ?\Closure $condition = null)
{
$instance = $this->resolver->resolve($concrete);

if (is_callable($instance)) {
return $this->resolver->handle($instance);
if (null !== $condition) {
$instance = $condition($instance) ?? $instance;
}

return $instance;
return $this->resolver->handle($instance);
}
}
3 changes: 2 additions & 1 deletion src/Container/ContainerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public function unset(string $id): void;
* Resolve an instance without adding it to the stack.
*
* @param string $concrete
* @param null|\Closure $condition
* @return mixed
*/
public function make(string $concrete);
public function make(string $concrete, ?\Closure $condition = null);
}
42 changes: 32 additions & 10 deletions src/Container/Resolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,21 @@ public function __construct(ContainerInterface $container)
* @param array $args
* @return mixed
*/
public function handle(callable $instance, array $args = [])
public function handle($instance, array $args = [])
{
$isInternalMethod = false;

if (is_string($instance) && false !== strpos($instance, '::')) {
$instance = explode('::', $instance);
} elseif (is_object($instance) && method_exists($instance, '__invoke')) {
$isInternalMethod = true;
$instance = [$instance, '__invoke'];
if (! $this->assertCallable($instance)) {
return $instance;
}

$params = [];
$reflector = ($isMethod = is_array($instance))
$isMethod = is_array($instance);
$isInternalMethod = $isMethod && $instance[1] === '__invoke';
$reflector = $isMethod
? new \ReflectionMethod($instance[0], $instance[1])
: new \ReflectionFunction($instance);

if ($isMethod) {
$params[] = is_object($instance[0]) ? $instance[0] : null;
$params[] = $instance[0];
feryardiant marked this conversation as resolved.
Show resolved Hide resolved
}

// If it was internal method resolve its params as a closure.
Expand Down Expand Up @@ -145,4 +142,29 @@ protected function resolveArgs(\ReflectionFunctionAbstract $callable, array $arg

return $args;
}

/**
* Assert $instance is callable.
*
* @param callable $instance
* @return bool
* @throws \BadMethodCallException When $instance is an array but the callable
* method not exists.
*/
private function assertCallable(&$instance): bool
{
if (is_string($instance) && false !== strpos($instance, '::')) {
$instance = explode('::', $instance);
} elseif (is_object($instance) && method_exists($instance, '__invoke')) {
$instance = [$instance, '__invoke'];
}

if (is_array($instance) && ! method_exists($instance[0], $instance[1])) {
throw new \BadMethodCallException(
sprintf('Call to undefined method %s::%s()', get_class($instance[0]), $instance[1])
);
}

return is_callable($instance);
}
}
31 changes: 31 additions & 0 deletions test/spec/Container.spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
$instances = [
Stubs\CallableClass::class => AbstractFoo::class,
Stubs\InstantiableClass::class => Stubs\InstantiableClass::class,
Stubs\SomeClass::class => Stubs\SomeClass::class,
];

foreach ($instances as $concrete => $instance) {
Expand All @@ -139,4 +140,34 @@
expect($this->c->has($concrete))->toBeFalsy();
}
});

it('Should make an instance without adding to the stack', function () {
// Dependencies.
$this->c->set('dummy', Dummy::class);
$this->c->set(AbstractFoo::class, ConcreteBar::class);

expect(
$this->c->make(Stubs\SomeClass::class)
)->toBeAnInstanceOf(Stubs\CertainInterface::class);

expect(
$this->c->make(Stubs\SomeClass::class, function ($instance) {
if ($instance instanceof Stubs\CertainInterface) {
return [$instance, 'handle'];
}

return null;
})
)->toEqual('lorem');

expect(function () {
$this->c->make(Stubs\SomeClass::class, function ($instance) {
if ($instance instanceof Stubs\CertainInterface) {
return [$instance, 'notExists'];
}

return null;
});
})->toThrow(new BadMethodCallException);
});
});
8 changes: 8 additions & 0 deletions test/stub/CertainInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Stubs;

interface CertainInterface
{
public function handle(AbstractFoo $dummy): string;
}
11 changes: 11 additions & 0 deletions test/stub/SomeClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Stubs;

class SomeClass implements CertainInterface
{
public function handle(AbstractFoo $dummy): string
{
return $dummy->lorem();
}
}