Dependency Injection Pattern seems extreme in Control Class - php

My Control Class basically picks which object / class to instantiate. Because this is basically what it does it naturally has many objects / classes it calls.
If I use dependency injection I will be injecting all of these objects. This seems bad for two reasons.
I've heard that about 3 dependent objects / classes is normal to KISS ( Keep it Simple Smarty)
Only one of the objects / classes will be used. So in a sense the others are instantiated for no reason.
How do I resolve these design considerations to satisfy - decoupled code, but simple and used code?

What you do is that you actually map some parameter onto some functionality, a so called script or action.
So in the end you only need a convention how to map that parameter or name onto some function. As functions can be somewhere (in some other object, in the global space, anonymous), you don't really need to inject many objects into your control class, but functions and the mapping.
If you would than even add some more differentiation with function name and parameters (or "modules" and "actions"), well then, you could drastically reduce your code and you can actually make the request inject the dependency:
Script or Action
Mapping: Actions:
"*" "_.Exception.Invalid ajax_type"
"signin_control" "A.SignIn.invoke"
"signup_control" "A.SignUp.invoke"
"tweet_control" "A.Tweet.add"
"ControlBookmark_add" "A.Bookmark.add"
"ControlBookmark_delete" "A.Bookmark.delete"
"ControlTryIt" "B.ControlTryIt"
"ControlSignOut" "C.SignOut"
Implementation:
$action = $map[isset($map[$ajax_type]) ? $ajax_type : '*'];
Session::start();
call_user_func_array(
'call_user_func_array',
explode('.', $action) + array(NULL, NULL, NULL)
);
function _($a, $b) {
throw new $a($b);
}
function A($a, $b) {
$maker = new ObjectMaker();
$maker->$a()->$b();
}
function B($a) {
new $a();
}
function C($a) {
Session::finish();
B($a);
}
This pseudo-code shows the actual business of your control class: Call some functions based on it's input. The concrete dependencies are:
ObjectMaker
Session
$map
As session is static, you should replace it with something that actually can be injected.
As $map is an array, it can be injected, but the logic of the mapping might need to become something more internal, so if $map is an ArrayAccess, this can happen already.
The non-concrete dependencies are hidden inside the actual $ajax_type, so these dependencies are dependent on that parameter through mapping, which is already a dependency. So the last dependency is:
$ajax_type
This dependency is related to both the control class and the mapping. So the control class itself could be made a dependency to the ajax type as well. But as you use a static global function, I'll simplify this inside a class function so actually dependencies can be passed into it. I put the factory into a global function and the ajax types are loaded from an ini-file:
function ajax_control_factory($inifile)
{
$maker = new ObjectMaker();
$session = new SessionWrap();
$types = new AjaxTypesIni($inifile);
return new AjaxControl($maker, $session, $types);
}
$control = ajax_control_factory($inifile);
printf("Call an nonexistent ajax type: ");
try {
$control->invokeByType('blurb');
printf(" - I so failed!\n");
} catch (Exception $e) {
printf("Exception caught! All good!\n");
}
printf("Add me a bookmark: ");
$control->invokeByType("ControlBookmark_add");
printf("Done! Fine! Superb this works!\n");
printf("Do the two control functions: ");
$control->invokeByType("ControlTryIt");
$control->invokeByType("ControlSignOut");
printf("Done! Fine! Superb this works!\n");
Ini file:
* = _.Exception.Invalid ajax_type
signin_control = A.SignIn.invoke
signup_control = A.SignUp.invoke
tweet_control = A.Tweet.add
ControlBookmark_add = A.Bookmark.add
ControlBookmark_delete = A.Bookmark.delete
ControlTryIt = B.ControlTryIt
ControlSignOut = C.SignOut
To have this work, this needs some stubs for mocking, which is easy with your example:
class Mock
{
public $stub;
public function __call($name, $args)
{
return class_exists($this->stub) ? new $this->stub() : $this->stub;
}
}
class ObjectMaker extends Mock
{
public $stub = 'Mock';
}
class ControlTryIt {}
class SignOut {}
class SessionWrap
{
public function start()
{
// session::start();
}
public function stop()
{
// session::finish();
}
}
Those are enough to run the code above which will give:
Call an nonexistent ajax type: Exception caught! All good!
Add me a bookmark: Done! Fine! Superb this works!
Do the two control functions: Done! Fine! Superb this works!
The ajax types:
class AjaxTypes extends ArrayObject
{
private $default;
private $types;
public function __construct(array $types, $default)
{
parent::__construct($types);
$this->default = $default;
}
public function offsetGet($index)
{
return parent::offsetExists($index) ? parent::offsetGet($index) : $this->default;
}
}
class AjaxTypesIni extends AjaxTypes
{
public function __construct($inifile)
{
$map = parse_ini_file($inifile);
if (!isset($map['*'])) throw new UnexpectedValueException('No * entry found.');
$default = $map['*'];
unset($map['*']);
parent::__construct($map, $default);
}
}
And the ajax controler:
class AjaxControl
{
private $types;
private $maker;
private $session;
public function __construct(ObjectMaker $maker, SessionWrap $session, AjaxTypes $types)
{
$this->types = $types;
$this->maker = $maker;
$this->session = $session;
}
public function invokeByType($type)
{
$session = $this->session;
$maker = $this->maker;
$invoke = function($action) use ($session, $maker)
{
$_ = function($a, $b)
{
throw new $a($b);
};
$A = function($a, $b) use ($maker)
{
$maker->$a()->$b();
};
$B = function ($a)
{
new $a();
};
$C = function ($a) use ($B, $session)
{
$session->stop();
$B($a);
};
$args = explode('.', $action) + array(NULL, NULL, NULL);
$func = array_shift($args);
call_user_func_array(${$func}, $args);
};
$invoke($this->types[$type]);
$this->session->start();
}
}
This is just exemplary. There is no guarantee that this fits as a design for your needs, just for demonstrating purposes. What it shows is that your actual controller function is not normalized / modular enough. When you better analyze the dependencies that exist and you inject them instead that you hardencode them, you will automatically find the best way to design your system.
What this example shows as well is that you have a tons of hidden dependencies for the request and response. You really need to draw lines somewhere and define what you pass through and in which direction. Say goodbye to global static state. Always inject. You can even start with function that need everything as parameters if it helps.

Solved:
By placing the dependency injection in the factory pattern ( Object Maker ), I can pull out all of the dependencies into one dependency - Object Maker - note below.
PHP Control
class Control
{
public static function ajax($ajax_type)
{
Session::start();
switch($ajax_type)
{
case 'signin_control': // uses Message, Text, Database
$Object = new ObjectMaker();
$ObjectSignIn=$Object->makeSignIn();
$ObjectSignIn->invoke();
break;
case 'signup_control':// uses Message, Text, Database
$Object = new ObjectMaker();
$ObjectSignUp=$Object->makeSignUp();
$ObjectSignUp->invoke();
break;
case 'tweet_control':// uses Message, Text, Database
$Object = new ObjectMaker();
$ObjectTweet=$Object->makeTweet();
$ObjectTweet->add();
break;
case 'ControlBookmark_add': // uses Message, Text, Database
$Object = new ObjectMaker();
$ObjectBookmark = $Object->makeBookmark();
$ObjectBookmark->add();
break;
case 'ControlBookmark_delete':// uses Database
$Object = new ObjectMaker();
$ObjectBookmark=$Object->makeBookmark();
$ObjectBookmark->delete();
break;
case 'ControlTryIt': // Why Not Session
new ControlTryIt();
break;
case 'ControlSignOut':
Session::finish();
new ControlSignOut();
break;
default:
throw new Exception('Invalid ajax_type');
}
}
ObjecMaker
class ObjectMaker
{
public function makeSignUp()
{
$DatabaseObject = new Database();
$TextObject = new Text();
$MessageObject = new Message();
$SignUpObject = new ControlSignUp();
$SignUpObject->setObjects($DatabaseObject, $TextObject, $MessageObject);
return $SignUpObject;
}
public function makeSignIn()
{
$DatabaseObject = new Database();
$TextObject = new Text();
$MessageObject = new Message();
$SignInObject = new ControlSignIn();
$SignInObject->setObjects($DatabaseObject, $TextObject, $MessageObject);
return $SignInObject;
}
public function makeTweet( $DatabaseObject = NULL, $TextObject = NULL, $MessageObject = NULL )
{
if( $DatabaseObject == 'small' )
{
$DatabaseObject = new Database();
}
else if( $DatabaseObject == NULL )
{
$DatabaseObject = new Database();
$TextObject = new Text();
$MessageObject = new Message();
}
$TweetObject = new ControlTweet();
$TweetObject->setObjects($DatabaseObject, $TextObject, $MessageObject);
return $TweetObject;
}
public function makeBookmark( $DatabaseObject = NULL, $TextObject = NULL, $MessageObject = NULL )
{
if( $DatabaseObject == 'small' )
{
$DatabaseObject = new Database();
}
else if( $DatabaseObject == NULL )
{
$DatabaseObject = new Database();
$TextObject = new Text();
$MessageObject = new Message();
}
$BookmarkObject = new ControlBookmark();
$BookmarkObject->setObjects($DatabaseObject,$TextObject,$MessageObject);
return $BookmarkObject;
}
}

Related

PHP How to detect if method is being called from public or private scope?

How can you detect if a method is being called from within a public, private or protected scope?
For example ...
class Foo {
public function getPassword(){
$scope = [??????];
switch($scope){
case 'public':
return "*****";
break;
case 'protected': case 'private':
return "IamPassword";
break;
}
}
}
Inside the class I might need a property that might not be visible for the template engine but accessible by the class.
First of all I would strongly recommend you to redesign your code as soon as possible. But nevertheless your question seemed interesting to me that is why you may try this:
$scopeIsInner = false;
$exception = new Exception();
$trace = $exception->getTrace();
$class = $trace[1]['class'];
if ($class == __CLASS__) {
$method = $trace[1]['function'];
$reflect = new ReflectionObject($this);
$methodList = $reflect->getMethods(ReflectionMethod::IS_PROTECTED | ReflectionMethod::IS_PRIVATE);
foreach ($methodList as $reflectionMethod) {
if ($method == $reflectionMethod->name) {
$scopeIsInner = true;
break;
}
}
}
var_dump($scopeIsInner);
P.S. I would never use this code in my own application

class substitution in php

Is there any way to make it work? See example :
class car {
function __construct($type){
switch ($type) {
case 'big' : return new big_car();
case 'small' : return new small_car();
}
}
function whatisit () {
echo "this is car ;( \n";
}
}
class big_car extends car {
function __construct(){}
function whatisit () {
echo "this is big car ;) \n";
}
}
class small_car extends car {
function __construct(){}
function whatisit () {
echo "this is small car ;) \n";
}
}
so the goal is to use it this way:
$mycar = new car('big');
$mycar->whatisit(); // i want it to say that it's big
I guess very much that its bad way and it cannot work this way but maybe there is a trick?
PS:: I know I can use special static method for that but...
You need a car factory to create new cars; this is not JavaScript :)
class car_factory
{
function create_car($type = null)
{
switch ($type) {
case 'big':
return new big_car();
case 'small':
return new small_car();
case null:
return new car();
}
throw new InvalidArgumentException($type);
}
}
$factory = new car_factory;
$small_car = $factory->create_car('small');
$std_car = $factory->create_car();
Of course, you should remove the __construct function from your original code.
As mentioned in the comments you could completely generalize this by using dynamic classes, assuming class extensions have the same constructor and class naming is consistent:
class car_factory
{
function create_car($type = null)
{
if (is_null($type)) {
return new car();
}
$class = "{$type}_car";
if (class_exists($class)) {
$obj = new $class();
if ($obj instanceof car) {
return $obj;
}
}
throw new InvalidArgumentException($type);
}
}
Personally I have no preferences either way; if extensibility is a key factor, go for it, otherwise stick with a simple switch.
[...]you could completely generalize this by using dynamic classes, assuming class extensions have the same constructor and class naming is consistent
You can add even more flexibility using Reflection:
class car_factory
{
function create_car($class = null, $constructorArgs = array())
{
if (is_null($class)) {
return new car();
}
try {
$refl = new ReflectionClass($class);
if (!$refl->isSubclassOf('car') {
throw new DomainException("Type: {$class} is not a car type");
}
return $refl->newIntanceArgs($constructorArgs);
} catch(ReflectionException $e) {
throw new DomainException("Invalid car type: {$class}");
}
}
}
Now use:
$factory = new car_factory();
$car1 = $factory->create_car('big_car');
$car2 = $factory->create_car('small_car');
$car3 = $factory->create_car('fancy_car_name_with_constructor_args', array("I'm fancy!"));

Wrong Static Method

PHP calls private method in parent class instead of method define in current class called by call_user_func
class Car {
public function run() {
return call_user_func(array('Toyota','getName')); // should call toyota
}
private static function getName() {
return 'Car';
}
}
class Toyota extends Car {
public static function getName() {
return 'Toyota';
}
}
$car = new Car();
echo $car->run(); //Car instead of Toyota
$toyota = new Toyota();
echo $toyota->run(); //Car instead of Toyota
I have found a solution with a different approach..
<?php
class Car {
public static function run() {
return static::getName();
}
private static function getName() {
return 'Car';
}
}
class Toyota extends Car {
public static function getName() {
return 'Toyota';
}
}
echo Car::run();
echo Toyota::run();
?>
Using Late Static Binding..
You might use something like this:
<?php
class Car {
public function run() {
return static::getName();
}
private static function getName(){
return 'Car';
}
}
class Toyota extends Car {
public static function getName(){
return 'Toyota';
}
}
$car = new Car();
echo $car->run();
echo PHP_EOL;
$toyota = new Toyota();
echo $toyota->run();
?>
Output:
Car
Toyota
PHP 5.4.5
This is a bug that appears to have fluctuated in and out of existence for a long time (see #deceze's tests in comments on the question). It is possible to "fix" this issue - that is, give consistent behaviour across PHP versions - using reflection:
Works in PHP 5.3.2 and later due to a dependency on ReflectionMethod::setAccessible() to invoke private/protected methods. I will add further explanation for this code, what it can and can't do and how it works very shortly.
Unfortunately it's not possible to test this directly on 3v4l.org because the code is too large, however this is the first ever real use case for minifying PHP code - it does work on 3v4l if you do this, so feel free to play around and see if you can break it. The only issue I'm aware of is that it doesn't currently understand parent. It is also restricted by the lack of $this support in closures before 5.4, there's not really anything that can be done about this though.
<?php
function call_user_func_fixed()
{
$args = func_get_args();
$callable = array_shift($args);
return call_user_func_array_fixed($callable, $args);
}
function call_user_func_array_fixed($callable, $args)
{
$isStaticMethod = false;
$expr = '/^([a-z_\x7f-\xff][\w\x7f-\xff]*)::([a-z_\x7f-\xff][\w\x7f-\xff]*)$/i';
// Extract the callable normalized to an array if it looks like a method call
if (is_string($callable) && preg_match($expr, $callable, $matches)) {
$func = array($matches[1], $matches[2]);
} else if (is_array($callable)
&& count($callable) === 2
&& isset($callable[0], $callable[1])
&& (is_string($callable[0]) || is_object($callable[0]))
&& is_string($callable[1])) {
$func = $callable;
}
// If we're not interested in it use the regular mechanism
if (!isset($func)) {
return call_user_func_array($func, $args);
}
$backtrace = debug_backtrace(); // passing args here is fraught with complications for backwards compat :-(
if ($backtrace[1]['function'] === 'call_user_func_fixed') {
$called = 'call_user_func_fixed';
$contextKey = 2;
} else {
$called = 'call_user_func_array_fixed';
$contextKey = 1;
}
try {
// Get a reference to the target static method if possible
switch (true) {
case $func[0] === 'self':
case $func[0] === 'static':
if (!isset($backtrace[$contextKey]['object'])) {
throw new Exception('Use of self:: in an invalid context');
}
$contextClass = new ReflectionClass($backtrace[$contextKey][$func[0] === 'self' ? 'class' : 'object']);
$contextClassName = $contextClass->getName();
$method = $contextClass->getMethod($func[1]);
$ownerClassName = $method->getDeclaringClass()->getName();
if (!$method->isStatic()) {
throw new Exception('Attempting to call instance method in a static context');
}
$invokeContext = null;
if ($method->isPrivate()) {
if ($ownerClassName !== $contextClassName
|| !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call private method in an invalid context');
}
$method->setAccessible(true);
} else if ($method->isProtected()) {
if (!method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call protected method in an invalid context');
}
while ($contextClass->getName() !== $ownerClassName) {
$contextClass = $contextClass->getParentClass();
}
if ($contextClass->getName() !== $ownerClassName) {
throw new Exception('Attempting to call protected method in an invalid context');
}
$method->setAccessible(true);
}
break;
case is_object($func[0]):
$contextClass = new ReflectionClass($func[0]);
$contextClassName = $contextClass->getName();
$method = $contextClass->getMethod($func[1]);
$ownerClassName = $method->getDeclaringClass()->getName();
if ($method->isStatic()) {
$invokeContext = null;
if ($method->isPrivate()) {
if ($ownerClassName !== $contextClassName || !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call private method in an invalid context');
}
$method->setAccessible(true);
} else if ($method->isProtected()) {
if (!method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call protected method in an invalid context');
}
while ($contextClass->getName() !== $ownerClassName) {
$contextClass = $contextClass->getParentClass();
}
if ($contextClass->getName() !== $ownerClassName) {
throw new Exception('Attempting to call protected method in an invalid context');
}
$method->setAccessible(true);
}
} else {
$invokeContext = $func[0];
}
break;
default:
$contextClass = new ReflectionClass($backtrace[$contextKey]['object']);
$method = new ReflectionMethod($func[0], $func[1]);
$ownerClassName = $method->getDeclaringClass()->getName();
if (!$method->isStatic()) {
throw new Exception('Attempting to call instance method in a static context');
}
$invokeContext = null;
if ($method->isPrivate()) {
if (empty($backtrace[$contextKey]['object'])
|| $func[0] !== $contextClass->getName()
|| !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call private method in an invalid context');
}
$method->setAccessible(true);
} else if ($method->isProtected()) {
$contextClass = new ReflectionClass($backtrace[$contextKey]['object']);
if (empty($backtrace[$contextKey]['object']) || !method_exists($method, 'setAccessible')) {
throw new Exception('Attempting to call protected method outside a class context');
}
while ($contextClass->getName() !== $ownerClassName) {
$contextClass = $contextClass->getParentClass();
}
if ($contextClass->getName() !== $ownerClassName) {
throw new Exception('Attempting to call protected method in an invalid context');
}
$method->setAccessible(true);
}
break;
}
// Invoke the method with the passed arguments and return the result
return $method->invokeArgs($invokeContext, $args);
} catch (Exception $e) {
trigger_error($called . '() expects parameter 1 to be a valid callback: ' . $e->getMessage(), E_USER_ERROR);
return null;
}
}
Use "protected" modifier if you want to get access from parent and descendants only. IMO, it's obvious. For example:
<?php
class Car {
public function run() {
return call_user_func(array('static','getName'));
}
protected static function getName() {
return 'Car';
}
}
class Toyota extends Car {
protected static function getName() {
return 'Toyota';
}
}
$car = new Car();
echo $car->run(); // "Car"
$toyota = new Toyota();
echo $toyota->run(); // "Toyota"
You can use get_called_class() instead of 'static'.
The problem is, I think, with the different access levels of the two getname functions. If you make the base class version of getname() public (the same as the derived class version), then in php 5.3.15 (on my Mac), you get Toyota. I think that, because of the different access levels, you end up with two different versions of the getname() function in the Toyota class, rather than the derived class version overriding the base class version. In other words, you have overloading rather than overriding. Therefore, when the run() function looks for a getname() function in the Toyota class to execute, it finds two and takes the first one, which would be the first to be declared (from the base class).
Granted this is just supposition on my part, but it sounds plausible.
use the get_called_called function todo this
public function run() {
$self = get_called_class();
return $self::getName();
}
I believe you're functions are overriding each other and by default going to the first one. Unless you change the parameters of one function, or rename the function it will always default to the parent class function.

Understanding desing patterns and OOP in PHP

i'm quite new to php and trying to learn. I have 2 similiar classes. I want to create that objects when i pass count and object type. I read some about factory pattern. Here is my factory class:
class AssetFactory
{
private static $table;
public static $objects = array();
public static function Create($asset,$count)
{
switch ($asset) {
case "Item":
self::$table = "items";
break;
case "Job":
self::$table = "jobs";
break;
}
$db = new Database();
$rows = $db->query("SELECT * FROM ".self::$table." LIMIT ".$count);
foreach($rows as $row)
{
self::$objects[] = new $asset($row);
}
return self::$objects;
}
}
and when i need 5 items i use:
$myItems = AssetFactory::Create('Item',5);
when i need some jobs i use:
$myJobs= AssetFactory::Create('Job',5);
item and job are that similiar classes. My question is here, as i said im trying to learn. Am i doing this right? Did i understand factory pattern right? Have any good documents about this(i read everything on php.net, got anything else).
There are few thing that seem wrong in this case.
First of all , there are two similar structures which are used for object creation:
factories: if object requires some sort of initialization before released for 'consumption'
builders: if before creating object you have to create bunch of other objects
Usually people do not distinguish between the two, and just call them "Factories". So these would be two case where you use a factory.
What you have right now does not fit the description. You are creating some sort of database connection, then getting some data, and then using it for creating a list of objects. This is not a reusable code.
It would be much better if the usage of factory would be something like this :
$connection = new PDO( .. blah.. );
$stmt = $connection->query( 'SELECT * FROM '.$type.' LIMIT '.$count );
$factory = new Factory;
$collection = $factory->buildCollection( $type, $stmt->fetchALL(PDO::FETCH_ASSOC) );
Of course, with factory class which implements this behavior.
Additionally , you might want to watch (assuming, that you haven't seen already) two videos on the subject:
Don't Look For Things!
Unit Testing
Global State and Singletons
I am far from an authority on the factory design pattern, but I usually delegate the instantiation to a subclass.
<?php
class AssetFactory
{
public static function Create($asset, $count)
{
$objects = false;
switch ( strtolower($asset) ) {
case 'item':
case 'job':
$class_name = 'Asset'.$asset;
$asset_obj = $class_name::getInstance();
$objects = $asset_obj->Create($count);
break;
default:
// Invalid asset
break;
}
return $objects;
}
}
class Asset
{
var $name = null;
var $table = null;
private static $instance = null;
private function __construct() {}
private function __clone() {}
public function Create($count)
{
$objects = array();
$db = new Database();
$rows = $db->query("SELECT * FROM ".$this->table." LIMIT ".$count);
if ( is_array($rows) ) {
foreach($rows as $row)
{
$objects[] = new Item($row);
}
}
return $objects;
}
public static function getInstance()
{
if ( empty($self::$instance) ) {
$class_name = __CLASS__;
self::$instance = new $class_name();
}
return self::$instance;
}
}
class AssetItem extends Asset
{
private function __construct()
{
$this->name = 'Item';
$this->table = 'item';
parent::__construct();
}
}
class AssetJob extends Asset
{
private function __construct()
{
$this->name = 'Job';
$this->table = 'job';
parent::__construct();
}
}

PHP OOP: What am I doing wrong?

I have a real hard time understanding why the below code doesn't work as intended. I've usually use the bucket dependency injector, but to simplify, I've used twittee below, with the very same result.
So why aren't my modified Config-object (and the created setting-element) available to the MockObject-class? From what I can tell, it's being passed correctly.
Code:
$c = new Container();
$c->config = function ($c) { return new Config(); };
$config = $c->config;
$config->setting = 'a value';
$c->MockObject = function ($c) { return new MockObject($c->config); };
$c->MockObject; // Error thrown: `Notice: Undefined index: setting`
Classes:
class Container {
protected $s=array();
function __set($k, $c) { $this->s[$k]=$c; }
function __get($k) { return $this->s[$k]($this); }
}
class Config {
public $values = array();
function __set($key, $value){ $this->values[$key] = $value; }
function __get($key) { return $this->values[$key]; }
}
class MockObject {
function __construct(Config $config) { echo $config->setting; }
}
Dependency injection container courtesy of Fabien Potencier; https://github.com/fabpot/twittee
I'm not extremely familiar with DI on PHP, but I think your problem is in this line:
$c->config = function ($c) { return new Config(); };
Your original code was
$config = $c->config = function ($c) { return new Config(); };
I'm guessing this threw an exception on $config->setting = 'a value'. $config and $c->config were both defined as a Closure that would return a new Config object. Since $config was a Closure, it would never have a setting property.
Your updated code is
$c->config = function ($c) { return new Config(); }; // $c->config is a closure as described
$config = $c->config; // $config is a new Config object
Now $config is being defined as a Config class, not a Closure, so $configure->setting is valid.
However, $c->config still refers to a Closure returning a new Config object. Since this new Config object doesn't have a property named "Setting" it's throwing an error when you try to retrieve it.
I'm not sure how it fits with the rest of your design, but the following should work as expected:
$c->MockObject = function ($c) { return new MockObject($config); };

Categories