Форум dkLab и Denwer
Здесь общаются Web-разработчики.
Генеральный спонсор:
Хостинг «Джино»

Наследование классов. Как узнать первоначальный класс с которого вызывался метод? (Александр Эсаулов, оценка: 1)
Author Message
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Fri Oct 16, 2009 10:01 am (написано за 34 секунды)
   Post subject: Наследование классов. Как узнать первоначальный класс с которого вызывался метод?
Reply with quote

Вопрос такой, в коде все написал.
Code (any language): скопировать код в буфер обмена
class A
{
        function Fun()
        {
                print __CLASS__.'<br />';         // Выдает A
                print get_class().'<br />'; // Выдает A
               
                // Как здесь узнать, что вызывался имеено класс B ?
        }
}

class B extends A
{

}

B::Fun();
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Fri Oct 16, 2009 10:17 am (спустя 15 минут; написано за 40 секунд)
   Post subject:
Reply with quote

ru.php.net/reflection в зубы - и вперёд!
Только вот в 99% случаев сие не нужно. Вы уверены, что попадаете в 1% исключения из правила?
Back to top
View user's profile Send private message
Миша Спларов
Участник форума



Joined: 17 Nov 2003
Posts: 821
Карма: 65
   поощрить/наказать

Location: Россия, Москва

PostPosted: Fri Oct 16, 2009 10:59 am (спустя 42 минуты; написано за 23 секунды)
   Post subject:
Reply with quote

В php 5.3 для статических методов есть get_called_class (ru2.php.net/manual/en/function.get-called-class.php)
Back to top
View user's profile Send private message
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Fri Oct 16, 2009 11:28 am (спустя 29 минут; написано за 1 минуту 15 секунд)
   Post subject:
Reply with quote

get_called_class() не на всех хостингах есть, поэтому не подойдет. В ReflectionClass я не нашел ни одного метода который мне возвратил нужное. Есть еще варианты?
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Fri Oct 16, 2009 1:06 pm (спустя 1 час 38 минут; написано за 1 минуту 18 секунд)
   Post subject:
Reply with quote

Александр Эсаулов
Я не понимаю, в чём проблема, просто перебираете родителей и их методы, находите нужное, радуетесь.
Back to top
View user's profile Send private message
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Fri Oct 16, 2009 1:29 pm (спустя 22 минуты; написано за 20 секунд)
   Post subject:
Reply with quote

WingedFox
Да в том то и дело, как перебрать? Примерчик.
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Fri Oct 16, 2009 2:19 pm (спустя 49 минут; написано за 33 секунды)
   Post subject:
Reply with quote

Вот, 3 нужные функции:
ru.php.net/manual/en/reflectionclass.getmethods.php
ru.php.net/manual/en/reflectionclass.getmethod.php
ru.php.net/manual/en/reflectionclass.getparentclass.php

Писать как ими пользоваться - лениво... =)
Back to top
View user's profile Send private message
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Fri Oct 16, 2009 2:45 pm (спустя 26 минут; написано за 2 минуты 24 секунды)
   Post subject:
Reply with quote

WingedFox
Я написал код. Но ничего не получилось. Я думаю что reflection тут не поможет.
Code (php): скопировать код в буфер обмена
<?
class A
{
        function Fun()
        {                               
                print (www.php.net/print) __CLASS__.'<br />';   // Выдает A
                print (www.php.net/print) get_class (www.php.net/get_class)().'<br />'; // Выдает A

                $ref=new ReflectionClass(get_class (www.php.net/get_class)());
               
                print (www.php.net/print) "<pre>\n\n";
               
                print (www.php.net/print) "getMethods:\n";
                print_r (www.php.net/print_r)($ref->getMethods());
               
                print (www.php.net/print) "\n\ngetMethod:\n";
                print_r (www.php.net/print_r)($ref->getMethod('Fun'));
               
                print (www.php.net/print) "\n\ngetParentClass:\n";
                print_r (www.php.net/print_r)($ref->getParentClass()); // $ref->getParentClass() Ничего не возвращает
               
                print (www.php.net/print) '</pre>';
               
                // Так и не получилось узнать, что метод вызывался именно через класс B
        }
}

class B extends A
{

}

B::Fun();
?>
То что выдало в браузер:
Code (any language): скопировать код в буфер обмена
A
A

getMethods:
Array
(
    [0] => ReflectionMethod Object
        (
            [name] => Fun
            [class] => A
        )

)


getMethod:
ReflectionMethod Object
(
    [name] => Fun
    [class] => A
)


getParentClass:
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Fri Oct 16, 2009 2:56 pm (спустя 10 минут; написано за 1 минуту 17 секунд)
   Post subject:
Reply with quote

Посмотрите ru.php.net/manual/en/reflectionclass.issubclassof.php
Если не взлетит - напишите разработчикам багрепорт.
Альтернатива - парсить скрипты вручную =)
Back to top
View user's profile Send private message
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Fri Oct 16, 2009 3:09 pm (спустя 13 минут; написано за 3 минуты 9 секунд)
   Post subject:
Reply with quote

WingedFox
public bool ReflectionClass::isSubclassOf ( string $class )
Возвращает true/false. Врядли мне это поможет. Ладно, вроде нашел вариант, связвнный с функцией get_called_class(). Для совместимости есть такой код:
Code (php): скопировать код в буфер обмена
<?
if(!function_exists (www.php.net/function_exists)('get_called_class'))
{
        function get_called_class($bt = false,$l = 1)
        {
                if (!$bt) $bt = debug_backtrace (www.php.net/debug_backtrace)();

                if (!isset (www.php.net/isset)($bt[$l])) throw new Exception("Cannot find called class -> stack level too deep.");
                if (!isset (www.php.net/isset)($bt[$l]['type'])) {
                        throw new Exception ('type not set');
                }
                else switch ($bt[$l]['type']) {
                        case '::':
                                $lines = file (www.php.net/file)($bt[$l]['file']);
                                $i = 0;
                                $callerLine = '';
                                do {
                                        $i++;
                                        $callerLine = $lines[$bt[$l]['line']-$i] . $callerLine;
                                } while (strpos (www.php.net/strpos)($callerLine,$bt[$l]['function']) === false);
                                preg_match (www.php.net/preg_match)('/([a-zA-Z0-9\_]+)::'.$bt[$l]['function'].'/',
                                                        $callerLine,
                                                        $matches);
                                if (!isset (www.php.net/isset)($matches[1])) {
                                        // must be an edge case.
                                        throw new Exception ("Could not find caller class: originating method call is obscured.");
                                }
                                switch ($matches[1]) {
                                        case 'self':
                                        case 'parent':
                                                return get_called_class($bt,$l+1);
                                        default:
                                                return $matches[1];
                                }
                                // won't get here.
                        case '->':
                                if(isset (www.php.net/isset)($bt[$l]['object']) && is_object (www.php.net/is_object)($bt[$l]['object']))
                                {
                                        $s=trim (www.php.net/trim)(print_r (www.php.net/print_r)($bt[$l]['object'],true));
                                        return substr (www.php.net/substr)($s,0,strpos (www.php.net/strpos)($s,' '));
                                }
                                else
                                {
                                        switch ($bt[$l]['function'])
                                        {
                                                case '__get':
                                                        // edge case -> get class of calling object
                                                        if (!is_object (www.php.net/is_object)($bt[$l]['object'])) throw new Exception ("Edge case fail. __get called on non object.");
                                                        return get_class (www.php.net/get_class)($bt[$l]['object']);
                                                default: return $bt[$l]['class'];
                                        }
                                }

                        default: throw new Exception ("Unknown backtrace method type");
                }
        }
}
?>
Хоть и связано с парсингом php кода, но все же работает. Но не всегда правильно.
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Fri Oct 16, 2009 3:34 pm (спустя 25 минут; написано за 25 секунд)
   Post subject:
Reply with quote

Александр Эсаулов
Я говорил проверить - определяется ли А как родитель B.
Back to top
View user's profile Send private message
dimagolov
Участник форума



Joined: 04 Feb 2007
Posts: 1664
Карма: 96
   поощрить/наказать

Location: Christ Church, Barbados

PostPosted: Fri Oct 16, 2009 3:35 pm (спустя 59 секунд)
   Post subject:
Reply with quote

Как-то в теме упустили самый важный момент, что необходимости в подобном шаманстве быть не должно, а если она есть, то что-то не правильно в архитектуре и/или понимании ООП
Back to top
View user's profile Send private message
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Fri Oct 16, 2009 4:11 pm (спустя 36 минут; написано за 14 минут 40 секунд)
   Post subject:
Reply with quote

WingedFox
В методе класса A я ничего не знаю о классе B. Классов которые наследуются от A будет много, и в методах класса A нужно знать имя класса с которого был вызван метод.
dimagolov
Даже незнаю, правильно или не правильно построена архитектура ООП. Но уже не изменить.
Есть один главный (назовем его так) класс, который производит различные операции с таблицами БД (основные добавление/удаление/выборка).
Есть классы, которые ссылаться на методы этого главного класса, передавая в параметре имя своего класса.
Вызванный метод главного класса определяет свойства (get_class_vars()) класса переданного в параметре и производит нужные действия. В свойствах описываются задействованые таблицы, их поля, типы полей, и.д. Вся логика работы зависит именно от описания свойств класса.

Это было создано для сокращения кол-ва кода, да и для более безошибочной работы. Делая изменения/дополнения в главном классе, изменения получают все классы.

Но, в этих классах приходится создавать вручную методы, такие же как и в главном. Это не удобно. Гораздо проще наследоваться с главного и иметь все его методы. Остается лишь одно, в методах главного класса узнать откуда он был вызван.
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Fri Oct 16, 2009 4:18 pm (спустя 6 минут; написано за 1 минуту 35 секунд)
   Post subject:
Reply with quote

Александр Эсаулов
Читайте внимательнее - имеет смысл проверить, определяется ли класс A как родитель B и если нет - надо писать багрепорт.
Конечно, это уже за пределами конкретной задачи... но, тем не менее, имеет смысл помочь сообществу.
Back to top
View user's profile Send private message
dimagolov
Участник форума



Joined: 04 Feb 2007
Posts: 1664
Карма: 96
   поощрить/наказать

Location: Christ Church, Barbados

PostPosted: Fri Oct 16, 2009 4:46 pm (спустя 27 минут; написано за 49 секунд)
   Post subject:
Reply with quote

Александр Эсаулов wrote:
Есть один главный (назовем его так) класс, который производит различные операции с таблицами БД (основные добавление/удаление/выборка).
Есть классы, которые ссылаться на методы этого главного класса, передавая в параметре имя своего класса.
Вызванный метод главного класса определяет свойства (get_class_vars()) класса переданного в параметре и производит нужные действия. В свойствах описываются задействованые таблицы, их поля, типы полей, и.д. Вся логика работы зависит именно от описания свойств класса.
это ORM такой?

Тут часом недавняя Стратегия (forum.dklab.ru/viewtopic.php?t=35453) не уместна?
Back to top
View user's profile Send private message
Миша Спларов
Участник форума



Joined: 17 Nov 2003
Posts: 821
Карма: 65
   поощрить/наказать

Location: Россия, Москва

PostPosted: Fri Oct 16, 2009 5:14 pm (спустя 27 минут; написано за 2 минуты 29 секунд)
   Post subject:
Reply with quote

Александр Эсаулов
Способ с debug_backtrace на сколько я помню по разному работает в php4 и в php5, если это играет для вас роль. А через Reflection точно можно сделать то, что вы хотите.
P. S. Вспомнилась занимательная задачка (phpclub.ru/talk/showthread.php?postid=814974#post814974).
Back to top
View user's profile Send private message
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Fri Oct 16, 2009 5:43 pm (спустя 28 минут; написано за 4 минуты 2 секунды)
   Post subject:
Reply with quote

Миша Спларов
Используется в любом случае PHP5. В занимательная задачке речь идет о методах. Там нет решения данной задачи. Будем тогда пока использовать debug_backtrace(), а что делать. Если есть готовое решение, прошу поделиться.
Back to top
View user's profile Send private message
Maus
Модератор



Joined: 29 Jun 2003
Posts: 8151
Карма: 270
   поощрить/наказать

Location: пос. Омсукчан Магаданской области

PostPosted: Fri Oct 16, 2009 7:01 pm (спустя 1 час 18 минут; написано за 3 минуты 51 секунду)
   Post subject:
Reply with quote

Александр Эсаулов wrote:
в методах класса A нужно знать имя класса с которого был вызван метод.
Не нужно.
Решить это можно двояко:
1) заводится protected свойство, и его значение перегружается (вручную) у каждого потомка.
2) посмотреть в сторону ключевого слово self: вроде бы оно должно помочь обойти проблему магической константы __CLASS__

Кстати, в том коде, что Вы приводили, как минимум небрежность: Вы нестатический метод вызывается как статический.
Back to top
View user's profile Send private message
Миша Спларов
Участник форума



Joined: 17 Nov 2003
Posts: 821
Карма: 65
   поощрить/наказать

Location: Россия, Москва

PostPosted: Fri Oct 16, 2009 7:05 pm (спустя 4 минуты; написано за 32 секунды)
   Post subject:
Reply with quote

Александр Эсаулов
Извиняюсь, я ошибся на счёт Reflection, вашу задачу с помощью него не решить.
Back to top
View user's profile Send private message
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Sat Oct 17, 2009 3:55 pm (спустя 20 часов 50 минут; написано за 1 минуту 30 секунд)
   Post subject:
Reply with quote

Maus
1) Вы конечно правы, но приведу пример.
Code (php): скопировать код в буфер обмена
<?
class A
{
        function aa()
        {
                print (www.php.net/print) $this->ClassName;
        }
}

class B extends A
{
        var $ClassName='This class B';
}

$obj=new B;
$obj->aa();

//
?>
Что если мы через "::" вызваем метод, как получить свойства вызываемого класса?
Back to top
View user's profile Send private message
Maus
Модератор



Joined: 29 Jun 2003
Posts: 8151
Карма: 270
   поощрить/наказать

Location: пос. Омсукчан Магаданской области

PostPosted: Sat Oct 17, 2009 5:29 pm (спустя 1 час 33 минуты; написано за 52 секунды)
   Post subject:
Reply with quote

Александр Эсаулов
Учите матчасть!
1) Статические методы и статические свойства.
2) var deprecated, нэ?
Back to top
View user's profile Send private message
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Mon Oct 19, 2009 10:54 am (спустя 1 день 17 часов 24 минуты; написано за 1 минуту 52 секунды)
   Post subject:
Reply with quote

Maus
1) есть одно решение, но опять же для PHP 5.3.0. Вот здесь описано ua2.php.net/oop5.late-static-bindings. Мне это не подходит, есть другие способы?
2) вот это я так и не понял, что это?
Back to top
View user's profile Send private message
dimagolov
Участник форума



Joined: 04 Feb 2007
Posts: 1664
Карма: 96
   поощрить/наказать

Location: Christ Church, Barbados

PostPosted: Mon Oct 19, 2009 3:36 pm (спустя 4 часа 41 минуту; написано за 1 минуту 35 секунд)
   Post subject:
Reply with quote

Александр Эсаулов, Вы бы посмотрели, как реолизованы другие ORM (e.g. sourceforge.net/projects/phplightorm/, www.doctrine-project.org/) и сделали бы нормальный рефакторинг своего кода, вместо выдумывания кривых костылей
Back to top
View user's profile Send private message
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Mon Oct 19, 2009 4:15 pm (спустя 39 минут; написано за 6 минут 25 секунд)
   Post subject:
Reply with quote

dimagolov
я считаю, что переделывать мне код не нужно. Если бы делал сейчас с нуля, всеравно так бы сделал.
Код прекрасно работает, вот только если бы удалось как то определять свойства или название класса наследника, удалось бы избавиться от некоторого кол-ва кода.

И так, еще раз привожу код:
Code (php): скопировать код в буфер обмена
<?
class A
{
        public static (www.php.net/static) function Fun()
        {
                // Как здесь получить значение свойства ClassName из класса "B" ?
                // Или название класса "B" ?
        }
}

class B extends A
{
        public static (www.php.net/static) $ClassName='This class B';
}

B::Fun();
Господа, давайте уже окончательно определимся, возможно ли это как то узнать для PHP<5.3.0? Если нет нормального способа, так и говорите. Дайте четкий ответ.
Back to top
View user's profile Send private message
Maus
Модератор



Joined: 29 Jun 2003
Posts: 8151
Карма: 270
   поощрить/наказать

Location: пос. Омсукчан Магаданской области

PostPosted: Mon Oct 19, 2009 4:54 pm (спустя 38 минут; написано за 4 минуты)
   Post subject:
Reply with quote

Признаю, был неправ. Действительно, всё упирается в то, что в PHP версий меньше 5.3 нет позднего связывания. Поэтому для статических вызовов способов нет.
Отсюда: почему бы Вам не создавать объект?

P.S. когда-то наталкивался на эту штуку со static, но уже забыл :((
Back to top
View user's profile Send private message
Guest






Карма: 387
   поощрить/наказать


PostPosted: Mon Oct 19, 2009 5:07 pm (спустя 13 минут; написано за 4 минуты 17 секунд)
   Post subject:
Reply with quote

Объект создавать не хочется, т.к. эти классы и используются уже в написании скриптов/сайтов. Отсюда, меньше кода (не нужно объявлять класс)... Более читабельный и понимаемый код... Новичку, который не силен в ООП, несложно разобраться(вызываются как функции, да и все)...

Да и изначально, я так спланировал и переделывать не собираюсь.
Back to top
Александр Эсаулов
Участник форума



Joined: 16 Oct 2009
Posts: 38
Карма: 0
   поощрить/наказать


PostPosted: Mon Oct 19, 2009 5:09 pm (спустя 2 минуты; написано за 12 секунд)
   Post subject:
Reply with quote

Извиняюсь, предыдущий пост мой.
Back to top
View user's profile Send private message
Valera2010
Guest





Карма: 387
   поощрить/наказать


PostPosted: Tue Jul 06, 2010 2:57 am (спустя 8 месяцев 17 дней 9 часов 47 минут; написано за 36 секунд)
   Post subject: http://php.net/manual/en/language.oop5.late-static-bindings.php
Reply with quote

используй в родителе static вместо self
php.net/manual/en/language.oop5.late-static-bindings.php
Back to top
Александр Михалицын
Модератор



Joined: 23 May 2008
Posts: 1299
Карма: 81
   поощрить/наказать


PostPosted: Tue Jul 06, 2010 4:42 am (спустя 1 час 45 минут; написано за 25 секунд)
   Post subject:
Reply with quote


!

Valera2010,
у нас на форуме принято общение на "Вы".
Back to top
View user's profile Send private message Send e-mail
Display posts from previous:   
Post new topic   Reply to topic All times are GMT + 3 Hours
Page 1 of 1    Email to a Friend.
You cannot post new topics in this forum. You cannot reply to topics in this forum. You cannot edit your posts in this forum. You cannot delete your posts in this forum. You cannot vote in polls in this forum. You cannot attach files in this forum. You can download files in this forum.
XML