Как я могу использовать __call для динамического возврата значений свойств - PullRequest
0 голосов
/ 28 октября 2010

Я пытался придумать способ динамического возврата значений свойств для класса с использованием __call вместо создания множества функций, единственной целью которых было бы возвращение этих значений. У меня есть идея запросить (например) $ this-> fetch_PersonFirstName () и проверить класс, если $ this-> person ["first_name"] установить и вернуть значение. Другой пример будет вызывать $ this-> fetch_BookGenreTitle () и заставить класс возвращать значение $ this-> book ["genre"] ["title"] . Я знаю, что что-то вроде этого должно было бы сделать небольшую проверку, чтобы автоматически определить, что, например, поскольку $ this-> book ["genre_title"] не существует, тогда оно должно проверьте наличие $ this-> book ["genre"] ["title"] .

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

Пожалуйста, напишите мне здесь. Я бился головой о стену, пытаясь понять это, и это убивает меня.

<?php

class Test
{
    protected $person;
    protected $book;

    public function __construct()
    {
        $this->person["first_name"] = "John Smith";
        $this->book["genre"]["title"] = "Suspense";
    }

    public function __call($method, $args)
    {
        $args = implode(", ", $args);

        if (preg_match("/^fetch_([A-Z]{1,}[a-z]{1,})(.*)?/", $method, $match))
        {
            print_r($match);
            echo "<br><br>";
            $property   = strtolower($match[1]);
            $indexes    = $match[2];

            if (property_exists("Test", $property))
            {
                if ($indexes)
                {
                    $indexes = preg_split("/(?<=[a-z])(?=[A-Z])/", $indexes);

                    $num_indexes    = count($indexes);
                    $count_indexes  = 1;

                    for ($count=0; $count<$num_indexes; $count++)
                    {
                        $record     = strtolower($indexes[$count]);
                        $index .= $record;
                        $array .= "{$record}";

                        $var_index  = $index;
                        $var_array  = $array;

                        echo $var_index." {$count}<br>";
                        echo $var_array." {$count}<br>";
                        //print_r($this->{$property}{$var_array});

                        if ($count_indexes == $num_indexes)
                        {
                            if (isset($this->{$property}{$var_index}))
                            {
                                return $this->{$property}{$var_index};
                            }
                            else
                            {
                                return $this->{$property}{$var_array};
                            }
                        }
                        else
                        {
                            $index .= "_";
                        }

                        $count_indexes++;
                    }
                    echo "<br><br>";
                }
                else
                {
                    return $this->{$property};
                }
            }
        }
    }
}
?>

<?php


    $test = new Test();
    echo $test->fetch_PersonFirstName();
    echo "<br><br>";
    echo $test->fetch_BookGenreTitle();
?>

Ответы [ 3 ]

1 голос
/ 28 октября 2010

Еще раз спасибо, ребята.Я думаю, что, наконец, у меня есть решение, которое работает для многомерных массивов или любой глубины и учитывает, является ли свойство, например, $ this-> book ["genre_title"] или $ this-> book ["genre"] ["title"] :)

Я публикую нижеприведенный код, поскольку кто-то другой может случайно найти его полезным в будущем

<?php

class Test
{
    protected $person;
    protected $book;

    public function __construct()
    {
        $this->person["first_name"] = "John Smith";
        $this->book["genre"]["title"] = "Suspense";
    }

    public function __get($var)
    {
        if (preg_match_all("/([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)/", $var, $matches))
        {
            $matches        = $matches[1];
            $property       = strtolower($matches[0]);

            if (property_exists($this, $property))
            {
                unset($matches[0]);

                $matches        = array_values($matches);
                $num_matches    = count($matches);

                $var = &$this->{$property};

                if (!$num_matches)
                {
                    return $var;
                }
                else
                {
                    foreach($matches as &$match)
                    {
                        $match  = strtolower($match);
                        $index .= $match;

                        if ($probe = $this->iterateArray($var, $index))
                        {
                            $var = $probe;
                            unset($index);
                        }
                        elseif ($probe = $this->iterateArray($var, $index))
                        {
                            $var = $probe;
                        }
                        else
                        {
                            $index .= "_";
                        }
                    }

                    return $var;
                }
            }
        }
    }

    public function iterateArray($var, $index)
    {
        if (array_key_exists($index, $var))
        {
            return $var[$index];
        }
        else
        {
            return false;
        }
    }
}
?>

<?php


    $test = new Test();
    echo $test->PersonFirstName;
    echo "<br><br>";
    echo $test->BookGenreTitle;
?>

Скорее всего, есть несколько способов улучшить / упростить код, и в этом случае любой желающий может с радостью опубликовать улучшенную версию.

0 голосов
/ 28 октября 2010

Учитывая "BookGenreTitle":

  1. Используйте какое-то регулярное выражение для разделения "Книга", "Жанр" и "Заголовок"
  2. property_exists($this, "Book")
  3. array_key_exists("genre", $this->book)
  4. Если ключ существует, вернуть $this->book["genre"]
  5. Если ключ не существует, array_key_exists("genre_title", $this->book)
  6. Если ключ существует, вернуть $this->book["genre_title"]
  7. Если ключ не существует, array_key_exists("genre", $this->book) && array_key_exists("title", $this->book["genre"])
  8. Продолжай идти

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

О, и как сказал другой автор, вам нужна перегрузка свойств (__get и __set).

0 голосов
/ 28 октября 2010

Вам нужно взглянуть на перегрузку свойства , а не перегрузку метода , как вы уже выяснили в заголовке вопроса.

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