PHP - это недоделанный язык
04.11.2008blogclient.ru/estdomains-pochil-v-boze.htm - пред запись на блоге Программы для блогов. В очередной раз меня достал PHP своей недоделанностью, точнее сырой объектной моделью. Из последнего, что меня достало, так это то, что late binding появился только в php 5.3 в качестве эксперимента что ли. Да, мля, но даже с этим все равно не получается красиво сделать некоторые простые штуки.
PHP - сука, противный язык. Например не работают очевидные простые конструкции:
$Object = $ClassName::Instance()
- ошибка парсинга кода, низя оказывается для :: использовать переменную, в которой находится имя класса. Ну ладно, выкрутился при
помощи$Object = TSomeClass::Instance()
- тоже не работает, так как внутри самого метода Instance невозможно определить имя класса, то есть получить TSomeClass, поскольку __class__
возвращает имя класса в котором находится определение Instance и следовательно для всех его потомков будет выдаваться только одно название родительского класса. В PHP 5.3 появился механизм
позднего связывания для статических методов. Можно было бы красиво разрулить ситуацию при помощи конструкции вида$ClassName = static::GetClassName()
где GetClassName прописать в
каждом классе в виде
public static function GetclassName() {
return __class__;
}
То есть без копипаста совсем не обойтись. Эй! Где вы апологеты PHP? Что за жопа этот ваш PHP? Если без копипаста не обойтись, то можно обойтись без и PHP 5.3 просто скопипастив целиком одну функцию Instance в каждый в класс. Что мне и пришлось сделать. Так что теперь каждый класс у меня начинается со следующего.
public static function &Instance() {
global $GlobalInstances;
$ClassName = __class__;
if (!isset($GlobalInstances[$ClassName])) {
$GlobalInstances[$ClassName] = &new $ClassName ();
}
return $GlobalInstances[$ClassName];
}
Мой блог находят по следующим фразам
• как можно заливать на narod.ru
• программы для T. sonic 610
• openvpn
• работа со строками в TLIstView
• кодировка сервера
• denwer файл баз данных
Комментарии (19) на запись “PHP - это недоделанный язык”
Пингбеки
Оставить комментарий
Не совсем понимаю, а чем не устраивает
class SomeClass {
public static getInstance() {
private static $instance = null;
}
}
теперь вкупе с __autoload нам всегда доступен класс
SomeClass::getInstance();
без глобалов.
извини, если не вник в твою супер-идею)
Не работает конструкция
$ClassName = 'SomeClass';
$Obj = $ClassName::GetInstance();
компилятор не допускает такой конструкции, но зато проходит на ура
$Obj = $GlobalInstances[$ClassName];
естественно обрамленной в отдельную функцию. В моей реализации объект можно запросить как и у тебя, так и через имя класса .
Скажи, пожалуйста, как с помощью локальной статической переменной разрулить?
А как на счет матчасть поизучать? или только орать горазд?
Индусней маяться и бурчать каждый может.
Почитай внимательней о функции get_called_class() .... авось поможет
abstract class Singleton {
private static $instances = array();
public function __construct() {
$class = get_called_class();
if (array_key_exists($class, self::$instances))
trigger_error("Tried to construct a second instance of class \"$class\"", E_USER_WARNING);
}
public static function getInstance() {
$class = get_called_class();
if (array_key_exists($class, self::$instances) === false)
self::$instances[$class] = new $class();
return self::$instances[$class];
}
}
А потом, ..... вуаля...
class A extends Singleton {
}
class B extends Singleton {
}
$a1 = A::getInstance();
$a2 = A::getInstance();
$b1 = B::getInstance();
$b2 = B::getInstance();
Если речь не о том какой язык лучше а о решении проблемы то внесу свою лепту. get_called_class конечно полезная функция, но пока php5.3 не получил должного распространения. Почему обязательно нужно брать instance из своего объекта?
class Singleton
{
private static $instances = array();
public static function get($classname)
{
if (isset(self::$instances[$classname])) return self::$instances[$classname];
return self::$instances[$classname] = new $classname;
}
}
Юзать:
include_once 'app.class.php';
$obj = Singleton::get('app');
P.S. просто отдельный класс который хранит instances ;)
и не надо ничего наследовать
ага, и везде писать имя класса в кавычках, отказавшись от
$instance = TClass::instance();
по меньшей мере в кавычках некрасиво, а к тому же ведет к потенциальным ошибкам в написании имени класса
Это все ерунда, меня вот лично в PHP убивает такие вещи:
Есть некий класс (описана его структура: поля/members)
Берем код:
class SomeClass
{
public $member;
}
$instance = new SomeClass();
unset($instance->member);
т.е. $instance вроде бы instanceof SomeClass (должен иметь св-во member, судя по описанию класса, а выходит он уже не SomeClass)
Вот полный код для демонстрации:
<?php
error_reporting(-1);
class SomeClass
{
protected $protectedMember;
public $publicMember;
public function __construct()
{
$this->protectedMember = 'Any secret value';
}
}
class HackerClass extends SomeClass
{
public function kill()
{
unset($this->protectedMember);
}
}
ob_start();
$test = new HackerClass();
var_dump($test);
unset($test->publicMember);
var_dump($test);
$test->kill();
var_dump($test);
file_put_contents(__FILE__ . '.txt', ob_get_clean());
echo 'Done';
?>
Вот, что вылетело в репорт (__FILE__ . '.txt')
object(HackerClass)#1 (2) {
["protectedMember:protected"]=>
string(16) "Any secret value"
["publicMember"]=>
NULL
}
object(HackerClass)#1 (1) {
["protectedMember:protected"]=>
string(16) "Any secret value"
}
object(HackerClass)#1 (0) {
}
Ну твой случай могут разрулить методы __*, а именно:
__get
__set
__unset
определить свое свойство member и например игнорировать удаление свойства. В php 5.3 еще больше возможностей
Идея моего поста - в том, что PHP нарушает правила ОПП, позволяя менять структуру объекта. Класс - это производная от Структуры.
Для чего придуманы структурированные данные?
Чтобы знать, что в этом типе есть этакое поле.
А про геттеры и сеттеры - это отдельная песня.
Во первых та возможность создания настоящих свойств (по терминам ООП: свойство - это в первую очередь интерфейс), которую дает PHP ч/з __get и __set, никуда не годится (скорость падает в 5-10 раз)
Вывод: нет и не было в PHP настоящего ООП, так только жалкое подобие, которое где-то на уровне JavaScript.
Да как не падает? Вот тест код:
<?php
error_reporting(-1);
class extClass extends stdClass
{
function __get($property)
{
return is_callable($accessor = array($this, __FUNCTION__ . $property))
? call_user_func($accessor)
: null;
}
function __set($property, $value)
{
if(is_callable($accessor = array($this, __FUNCTION__ . $property)))
call_user_func($accessor, $value);
else
$this->$property = $value;
}
}
class TestClass extends extClass
{
private $property = '';
protected function __getProperty()
{
return $this->property;
}
protected function __setProperty($value)
{
$this->property = (string) $value;
}
public $member;
}
ob_start();
$test = new TestClass();
$microtime = microtime(true);
for($index = 0; $index < 10000; $index++) $test->member = 'This is TEST';
echo 'MEMBER SET = ' . (microtime(true) - $microtime) . PHP_EOL;
$microtime = microtime(true);
for($index = 0; $index < 10000; $index++) $test->property = 'This is TEST';
echo 'PROPERTY SET = ' . (microtime(true) - $microtime) . PHP_EOL;
echo '--------------------------------------------------------------' . PHP_EOL;
$microtime = microtime(true);
for($index = 0; $index < 10000; $index++) $value = $test->member;
echo 'MEMBER GET = ' . (microtime(true) - $microtime) . PHP_EOL;
$microtime = microtime(true);
for($index = 0; $index < 10000; $index++) $value = $test->property;
echo 'PROPERTY GET = ' . (microtime(true) - $microtime) . PHP_EOL;
file_put_contents(__FILE__ . '.txt', ob_get_clean());
echo 'The all test are done ...';
?>
Вот результат для CLI:
MEMBER SET = 0.00308680534363
PROPERTY SET = 0.0497620105743
MEMBER GET = 0.00220513343811
PROPERTY GET = 0.0464649200439
И еще самое главное неудобство при таком подходе - это то, что
ни одна IDE не дает подсказку IntelliSense для даких свойств (__get/__set), поскольку таких свойств нет в описании класса.