Банально, но ;) пишу CMF и предлагаю познакомиться и ищу единомышленников для дальшейшей разработки.

d1gi

Новичок
что то не заводиться(дохнет в рекурсии), какие модули нужны для работы?
ээм... сначала надо знать что вы делаете... и посмотреть ваш phpinfo(), вообще давно уже нет глюков с развертыванием.

единственное, на локалке надо ставить проект взятый из архива, например тут https://github.com/d1gi/Smart-Core-CMF/downloads, а не просто стянутый с репы т.к. нехочу в репу загружать все сторонние либы.

p.s. большое фи за использование eval
да, евал пришлось вставить, потому что незнаю как нативно решить эту задачу...
PHP:
eval('self::$_instances[$class] = new $class(' . $args . ');');
если кто подскажет, буду благодарен!
 

флоппик

promotor fidei
Команда форума
Партнер клуба
по-моему, эта строчка прекрасно выполнится и без эвала
 

d1gi

Новичок
по-моему, эта строчка прекрасно выполнится и без эвала
суть этого класса заключается в том, что в конструктор можно передать произвольное кол-во методов, и они все будут переданы конструктору вызываемого класса:
PHP:
abstract class Singleton
{
	private static $_instances = array();
	protected function __construct() {
		parent::__construct();
	}
	private function __clone() {}
	private function __wakeup() {}

	public static function getInstance()
	{
		$class = get_called_class();
		if (!isset(self::$_instances[$class])) {
			if (func_num_args() == 0) {
				self::$_instances[$class] = new $class();
			} else {
				$cnt = func_num_args();
				
				$args = '';
				foreach (func_get_args() as $value) {
					// @todo объекты пока нельзя передать как аргумент.
					if (is_object($value)) {
						die ('Singleton does not support object as constructor argument, yet.');
					}
					// Числа добавляются в строку аргументов без экранирования.
					elseif (is_numeric($value)) {
						$args .= $value;
					}
					// Массивы и строки преобразовываются в PHP код.
					else {
						ob_start();
						ob_implicit_flush(false);
						var_export($value);
						$args .= ob_get_clean();
					}
					
					if (--$cnt !== 0) {
						$args .= ', ';
					}
				}
				eval('self::$_instances[$class] = new $class(' . $args . ');');
			}
		}
		return self::$_instances[$class];
	}	
}
пока решил так, но как вариант, можно либо отказаться вообще от аргументов для конструктора, либо жестко захардкодить несколько случаев, например от 0 до 5 аргументов и нативно в каждом случае вызывать создание объекта с нужным синтаксисом...
 

fixxxer

К.О.
Партнер клуба
PHP:
            $instance = call_user_func_array(
                array(new \ ReflectionClass($class_name), 'newInstance'),
                $constructor_arguments
            );
 

~WR~

Новичок
У var_export есть второй аргумент, который позволяет обойтись без ob_start.
 

wadim

Новичок
и так:
PHP:
class test {
	public function __construct($ololo, $ololo2) {
		echo $ololo, $ololo2;
	}
}

$args = array('test1', 'test2');
$class = new ReflectionClass('test');
$newClass = $class->newInstanceArgs($args);
 

d1gi

Новичок
wadim

т.к. class Singleton синглтон поразумевает, что вызываемые классы будут иметь не публичный конструктор, то метод ReflectionClass::newInstanceArgs сгенерирует ошибку.
 

Ragazzo

TDD interested
d1gi
тогда стоит отказаться, от такой "фичи", и переделать нормально, без хитрой архитектуры :)
 

d1gi

Новичок
проверил и был прав, вот такой код работает как часы :)
PHP:
abstract class Singleton extends Base
{
	private static $_instances = array();
	protected function __construct() {
		parent::__construct();
	}
	private function __clone() {}
	private function __wakeup() {}

	public static function getInstance()
	{
		$class_name = get_called_class();
		
		if (!isset(self::$_instances[$class_name])) {
			$args = func_get_args();
			switch (func_num_args()) {
				case 0:
					self::$_instances[$class_name] = new $class_name();
					break;
				case 1:
					self::$_instances[$class_name] = new $class_name($args[0]);
					break;
				case 2:
					self::$_instances[$class_name] = new $class_name($args[0], $args[1]);
					break;
				case 3:
					self::$_instances[$class_name] = new $class_name($args[0], $args[1], $args[2]);
					break;
				default;
			}
		}
		
		return self::$_instances[$class_name];
	}	
}
тут можно еще генерацию ошибки добавить например если програмер захочет передать больше 3-х аргументов, хотя сейчас в проекте используется максимум 2 аргумента.

в архитектуре ничего хитрого нет, просто Reflection API может работать только с публичным конструктором... зато такой класс синглтона помогает заметно упростить код.
 

fixxxer

К.О.
Партнер клуба
ваш вариант также не работает т.к. требуется создавать новый объект класса, а не просто вызвать статический метод.
Да что вы говорите. А проверить? Это взято из рабочей реализации registry с lazy initialization если че.

Раз вы такой ленивый, вот делаю за вас

PHP:
<?php

class A {
    public function __construct($foo, $bar) {
        echo "I am created! foo = '$foo', bar = '$bar'\n";
    }
}

function _new($class_name, array $args) {
    return call_user_func_array(
        array(new \ ReflectionClass($class_name), 'newInstance'),
        $args
    );
}

_new('A', array(1,2));
_new('A', array(3,4));
Код:
fixxxer@mbp ~/tmp$ php 0.php 
I am created! foo = '1', bar = '2'
I am created! foo = '3', bar = '4'
 

fixxxer

К.О.
Партнер клуба
А, понял, вижу. А захрена так делать, синглтона достаточно одного - Registry (или какой-нить service locator).

Мало того, тут еще и предок зачем-то знает о потомках, получается. Два антипаттерна сразу.

То, что вообще пришла в голову идея сделать удобным управление пачкой синглтонов, говорит о плохой архитектуре. Непродуманная архитектура, в свою очередь, порождает странные желания и странный код.

Там что-то говорили о тестах, которые "писать некогда" - ну, ну. Подозреваю, что дело вовсе не в этом: я бы с нескрываемым интересом посмотрел, как ТС станет эти дела покрывать тестами ;)
 

wadim

Новичок
fixxxer
в это уже загадка ведомая только автору,

PHP:
// Конфиг по умолчанию.
$config = array(
	'cron_key'		 => false,
	'db_name' 		 => 'smart_core',
   //code
	);

// Наложение конфига платформы на системный конфиг.
foreach ($cfg_ini as $key => $value) {
	$config[$key] = $value;
}
почему не:
PHP:
$config = array_merge($config, $cfg_ini);
а это только на поверхности.
 

fixxxer

К.О.
Партнер клуба
Кстати, любителей острых ощущений и особых извращений спасет php 5.4.

http://www.php.net/manual/en/reflectionclass.newinstancewithoutconstructor.php

PHP:
fixxxer@mbp ~/tmp$ cat 0.php 
<?php

class IWannaDoStrangeThings {

    protected function __construct($foo, $bar) {
        echo "I'm created! foo = '$foo', bar = '$bar'\n";
    }

    public static function ctor(array $args) {
        $ReflectionClass = new ReflectionClass(get_called_class());
        $Instance = $ReflectionClass->newInstanceWithoutConstructor();
        call_user_func_array( array($Instance, '__construct'), $args );
    }

}

IWannaDoStrangeThings::ctor(array(1,2));
Код:
fixxxer@mbp ~/tmp$ ./php-5.4.0beta2/sapi/cli/php 0.php 
I'm created! foo = '1', bar = '2'
 

d1gi

Новичок
Проведен крупный рефакторинг кода, теперь более явно прорисовывается паттерн MVC, но в данном движке, в связи с особенностями архитектуры — HMVC :) функциональных изменений нет, на данный момент даже может быть наоборот, что-то может еще неработать из того, что работало раньше ;) в общем огрехов еще много, но сейчас код стал проще, чем был ;)

Скачать как обычно можно отсюда http://smart-core.org/. Код смотреть удобнее тут https://github.com/d1gi/Smart-Core-CMF.
 
Сверху