如何使用 __call 动态返回属性值

发布于 2024-09-29 13:01:31 字数 3104 浏览 2 评论 0原文

我一直在尝试想出一种使用 __call 动态返回类的属性值的方法,而不是创建大量其唯一目的是返回这些值的函数。我的想法是能够请求(例如)$this->fetch_PersonFirstName()并让类检查是否$this->person["first_name"]< /strong> 设置并返回值。另一个例子是调用 $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();
?>

I've been trying to think of a way to dynamically return property values for a class using __call instead of creating a slew of functions whose only purpose would be to return those values. The idea I have is to be able to request ( for example ) $this->fetch_PersonFirstName() and have the class check if $this->person["first_name"] is set and return the value. Another example would be calling $this->fetch_BookGenreTitle() and have the class return the value of $this->book["genre"]["title"]. I know something like this would have to do a bit of checking in order for it to automatically determine that, for example, since $this->book["genre_title"] doesn't exist, then it should check for $this->book["genre"]["title"].

So far I've come up with code that ( for some reason ) works for returning the values of an array ( such as my person example ) but my problem quickly develops when I try to return the values of a multidimensional array ( such as with my above book example ). Bare in mind, I'm still trying to think of a way for the __call method to check for the existence of one, and if it doesn't exist, then the other.

Please, throw me a line here. I've been banging my head against the wall trying to figure this out and it's killing me.

<?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();
?>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千紇 2024-10-06 13:01:31

再次感谢各位。我想我终于有了我的解决方案,它适用于多维数组或任何深度,并考虑确定属性是否为,例如 $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;
?>

很有可能有一些方法来改进/简化代码,在这种情况下,非常欢迎任何想要这样做的人发布改进的版本。

Thanks again folks. I think I finally have my solution, which works for multidimensional arrays or any depth and accounts for determining whether a property is, for example $this->book["genre_title"] or $this->book["genre"]["title"] :)

I'm posting the code below as someone else may randomly find it useful in the future

<?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;
?>

There's more than likely some ways to improve/streamline the code, in which case anyone wanting to do so is more than welcome to post an improved version.

风铃鹿 2024-10-06 13:01:31

给定“BookGenreTitle”:

  1. 使用某种正则表达式来分隔“Book”、“Genre”和“Title”
  2. property_exists($this, "Book")
  3. array_key_exists("genre", $ this->book)
  4. 如果 key 存在,则返回 $this->book["genre"]
  5. 如果 key 不存在,则 array_key_exists("genre_title", $ this->book)
  6. 如果 key 存在,则返回 $this->book["genre_title"]
  7. 如果 key 不存在,则 array_key_exists("genre", $这本书)&& array_key_exists("title", $this->book["genre"])
  8. 继续

可能有一种方法可以使用循环或某种递归而不是硬编码最大深度,但我不会'现在就开始吧……

哦,正如另一位发帖者所说,您想要的是属性重载(__get__set)。

Given "BookGenreTitle" :

  1. Use some sort of regex to separate "Book", "Genre", and "Title"
  2. property_exists($this, "Book")
  3. array_key_exists("genre", $this->book)
  4. If key exists, return $this->book["genre"]
  5. If key doesn't exist, array_key_exists("genre_title", $this->book)
  6. If key exists, return $this->book["genre_title"]
  7. If key doesn't exist, array_key_exists("genre", $this->book) && array_key_exists("title", $this->book["genre"])
  8. Keep going

There's probably a way to use a loop or some sort of recursion instead of hard-coding the maximum depth, but I won't get into that now...

Oh, and as the other poster said, what you want is property overloading (__get and __set).

芯好空 2024-10-06 13:01:31

You need to take a look at property overloading, not method overloading as you've already figured out in the question's title yourself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文