| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 | 
							- <?php
 
- namespace Elgg\Di;
 
- /**
 
-  * Container holding values which can be resolved upon reading and optionally stored and shared
 
-  * across reads.
 
-  *
 
-  * <code>
 
-  * $c = new \Elgg\Di\DiContainer();
 
-  *
 
-  * $c->setFactory('foo', 'Foo_factory'); // $c will be passed to Foo_factory()
 
-  * $c->foo; // new Foo instance
 
-  * $c->foo; // same instance
 
-  *
 
-  * $c->setFactory('bar', 'Bar_factory', false); // non-shared
 
-  * $c->bar; // new Bar instance
 
-  * $c->bar; // different Bar instance
 
-  *
 
-  * $c->setValue('a_string', 'foo_factory'); // don't call this
 
-  * $c->a_string; // 'foo_factory'
 
-  * </code>
 
-  *
 
-  * @access private
 
-  * 
 
-  * @package Elgg.Core
 
-  * @since   1.9
 
-  */
 
- class DiContainer {
 
- 	/**
 
- 	 * @var array each element is an array: ['callable' => mixed $factory, 'shared' => bool $isShared]
 
- 	 */
 
- 	protected $factories = array();
 
- 	/**
 
- 	 * @var array
 
- 	 */
 
- 	protected $cache = array();
 
- 	const CLASS_NAME_PATTERN_53 = '/^(\\\\?[a-z_\x7f-\xff][a-z0-9_\x7f-\xff]*)+$/i';
 
- 	/**
 
- 	 * Fetch a value.
 
- 	 *
 
- 	 * @param string $name The name of the value to fetch
 
- 	 * @return mixed
 
- 	 * @throws \Elgg\Di\MissingValueException
 
- 	 */
 
- 	public function __get($name) {
 
- 		if (array_key_exists($name, $this->cache)) {
 
- 			return $this->cache[$name];
 
- 		}
 
- 		if (!isset($this->factories[$name])) {
 
- 			throw new \Elgg\Di\MissingValueException("Value or factory was not set for: $name");
 
- 		}
 
- 		$value = $this->build($this->factories[$name]['callable'], $name);
 
- 		// Why check existence of factory here? A: the builder function may have set the value
 
- 		// directly, in which case the factory will no longer exist.
 
- 		if (!empty($this->factories[$name]) && $this->factories[$name]['shared']) {
 
- 			$this->cache[$name] = $value;
 
- 		}
 
- 		return $value;
 
- 	}
 
- 	/**
 
- 	 * Build a value
 
- 	 * 
 
- 	 * @param mixed  $factory The factory for the value
 
- 	 * @param string $name    The name of the value
 
- 	 * @return mixed
 
- 	 * @throws \Elgg\Di\FactoryUncallableException
 
- 	 */
 
- 	protected function build($factory, $name) {
 
- 		if (is_callable($factory)) {
 
- 			return call_user_func($factory, $this);
 
- 		}
 
- 		$msg = "Factory for '$name' was uncallable";
 
- 		if (is_string($factory)) {
 
- 			$msg .= ": '$factory'";
 
- 		} elseif (is_array($factory)) {
 
- 			if (is_string($factory[0])) {
 
- 				$msg .= ": '{$factory[0]}::{$factory[1]}'";
 
- 			} else {
 
- 				$msg .= ": " . get_class($factory[0]) . "->{$factory[1]}";
 
- 			}
 
- 		}
 
- 		throw new \Elgg\Di\FactoryUncallableException($msg);
 
- 	}
 
- 	/**
 
- 	 * Set a value to be returned without modification
 
- 	 *
 
- 	 * @param string $name  The name of the value
 
- 	 * @param mixed  $value The value
 
- 	 * @return \Elgg\Di\DiContainer
 
- 	 * @throws \InvalidArgumentException
 
- 	 */
 
- 	public function setValue($name, $value) {
 
- 		$this->remove($name);
 
- 		$this->cache[$name] = $value;
 
- 		return $this;
 
- 	}
 
- 	/**
 
- 	 * Set a factory to generate a value when the container is read.
 
- 	 *
 
- 	 * @param string   $name     The name of the value
 
- 	 * @param callable $callable Factory for the value
 
- 	 * @param bool     $shared   Whether the same value should be returned for every request
 
- 	 * @return \Elgg\Di\DiContainer
 
- 	 * @throws \InvalidArgumentException
 
- 	 */
 
- 	public function setFactory($name, $callable, $shared = true) {
 
- 		if (!is_callable($callable, true)) {
 
- 			throw new \InvalidArgumentException('$factory must appear callable');
 
- 		}
 
- 		$this->remove($name);
 
- 		$this->factories[$name] = array(
 
- 			'callable' => $callable,
 
- 			'shared' => $shared
 
- 		);
 
- 		return $this;
 
- 	}
 
- 	/**
 
- 	 * Set a factory based on instantiating a class with no arguments.
 
- 	 *
 
- 	 * @param string $name       Name of the value
 
- 	 * @param string $class_name Class name to be instantiated
 
- 	 * @param bool   $shared     Whether the same value should be returned for every request
 
- 	 * @return \Elgg\Di\DiContainer
 
- 	 * @throws \InvalidArgumentException
 
- 	 */
 
- 	public function setClassName($name, $class_name, $shared = true) {
 
- 		$classname_pattern = self::CLASS_NAME_PATTERN_53;
 
- 		if (!is_string($class_name) || !preg_match($classname_pattern, $class_name)) {
 
- 			throw new \InvalidArgumentException('Class names must be valid PHP class names');
 
- 		}
 
- 		$func = function () use ($class_name) {
 
- 			return new $class_name();
 
- 		};
 
- 		return $this->setFactory($name, $func, $shared);
 
- 	}
 
- 	/**
 
- 	 * Remove a value from the container
 
- 	 * 
 
- 	 * @param string $name The name of the value
 
- 	 * @return \Elgg\Di\DiContainer
 
- 	 */
 
- 	public function remove($name) {
 
- 		unset($this->cache[$name]);
 
- 		unset($this->factories[$name]);
 
- 		return $this;
 
- 	}
 
- 	/**
 
- 	 * Does the container have this value
 
- 	 * 
 
- 	 * @param string $name The name of the value
 
- 	 * @return bool
 
- 	 */
 
- 	public function has($name) {
 
- 		return isset($this->factories[$name]) || array_key_exists($name, $this->cache);
 
- 	}
 
- }
 
 
  |