草庐IT

php - 与 __get_state() 之类的 __set_state() 相反?

coder 2024-01-03 原文

__set_state() 是否有一个与 __get_state() 相反的 PHP 函数?我的意思不是 __sleep() 用于序列化。我想要一个简单的函数,它在对象上调用 var_export() 之后但在 var_export() 获取数据之前调用,这样我就可以在每个对象上选择哪些数据将是导出。 我知道有一种方法可以通过 __get()debug_backtrace() 实现,仅在 var_export() 时修改数据在一个对象上被调用。 但是有更简单的方法吗?

编辑:没有办法用__get()debug_backtrace()来实现,只有在时才修改数据var_export() 在对象上调用,因为 __get() 未在 var_export() 上调用。

解决方案:

<?php
/*
 * @author Christian Mayer <http://fox21.at>
 * @link http://stackoverflow.com/q/21762276/823644
 * @link https://eval.in/163041
 * @link https://eval.in/163462
 * @link https://eval.in/163909
 * @link https://gist.github.com/TheFox/49ff6903da287c30e72f
 */

interface Exportable{
    public function __get_state();
}

function unset_with_get_state($expression){
    $before = clone $expression;
    $classVars = array_keys(get_class_vars(get_class($before)));
    foreach(array_diff($classVars, $before->__get_state()) as $var){
        unset($before->$var);
    }
    return $before;
}

function my_var_export($expression, $return = null){
    $before = $expression;
    if($before instanceof Exportable){
        $before = unset_with_get_state($expression);
    }
    return var_export($before, $return);
}

class Foo implements Exportable{
    public $name = null;
    public $foo = null;
    public $bar = null;

    public function __get_state(){
        // Only show 'name' and 'bar' on my_var_export().
        return array('name', 'bar');
    }
}

$a = 'hello';
my_var_export($a);
print "\n";

$b = new Foo();
$b->name = 'world';
$b->foo = 'foo is foo';
$b->bar = 'bar is bar';
my_var_export($b);
print "\n";

当然,通过自己的实现,您可以做任何事情。使用 有更简单的方法吗? 我的意思是如果有内置的 PHP 函数或类似的东西,那么您就不必自己动手了。这个解决方案并不是很简单,因为您必须从Exportable 扩展您的所有对象。这也仅在您的变量为 public 时有效。在此示例中,我选择仅导出 namebar 而不是 foo。一个内置的 PHP 函数(如 __set_state() 是)会更好。

最佳答案

你在问题​​中写下:

I want a simple function which is called after var_export() is called on a object but before var_export() gets the data

这听起来像是您想采用 var_export() 函数,然后调用适配器而不是 var_export()。然后在适配器内部你会得到数据 before 它是(真的)var_export()ed:

function my_var_export($expression, $return = NULL) {
    $before = $expression;
    return var_export($before, $return);
}

$a = 'hello';
my_var_export($a); // 'hello'

有了这个适配器,您就可以在技术上确定您正在寻找的东西,但这也是先决条件。

所以我们关心的是对象,而不是字符串。对于那些对象,应该调用 __get_state() 方法。由于我们目前知道这样的对象应该是什么(它应该是可导出的),我们创建一个接口(interface):

interface Exportable {
    /**
     * @return static clone of $this for var_export
     */
    public function __get_state();
}

那么如何实现呢?一种想法是克隆真实对象然后更改它,这样 var_export 就不会遇到任何问题。这种克隆将使我们免于操作具体对象只是为了导出它。但这只是一个约定,一个不能被克隆的对象也可以实现这个__get_state()方法,到时候写实现可能会稍微复杂一些。

另一方面,在接口(interface)的帮助下,适配器 my_var_export() 可以更智能地处理 $before 传递给var_export():

function my_var_export($expression, $return = null)
{
    $before = $expression instanceof Exportable
        ? $expression->__get_state()
        : $expression;

    return var_export($before, $return);
}

只是插入了一个Exportable $expression 需要特殊处理的新案例。对于 $a = 'hello'; 表达式,这与以前一样有效。

现在开始吧,我们需要一个Exportable 的具体类型,示例性的我在这里使用了Foo。出于测试目的,我给它一个私有(private)属性,只有在 __get_state() 的实现在采用的 var_export() 操作中被调用时才会设置:

class Foo implements Exportable
{
    private $name = null;
    private $__get_state_called;

    public function __construct($name)
    {
        $this->name = (string)$name;
    }

    public function __get_state()
    {
        $before = clone $this; // or if inherited: parent::__get_state()

        $before->__get_state_called = true;

        return $before;
    }
}

工作示例是:

$b = new Foo('hello');
my_var_export($b);

根据需要给出输出:

Foo::__set_state(array(
   'name' => 'hello',
   '__get_state_called' => true,
))

这就是您的“魔法”函数 __get_state() var_export() 获取数据但之后 (my_)var_export() 被调用。

调整函数 var_export 以添加您需要的功能。为需要特殊处理的对象使用接口(interface)。

完整示例 ( run it online ):

<?php
/*
 * @author hakre <http://hakre.wrodpress.com/>
 * @link http://stackoverflow.com/a/24228153/367456
 * @link https://eval.in/163041
 */

/**
 * Interface Exportable
 */
interface Exportable
{
    /**
     * @return static clone of $this for var_export
     */
    public function __get_state();
}

/**
 * @param mixed $expression
 * @param bool  $return (optional)
 *
 * @return void|string
 */
function my_var_export($expression, $return = null)
{
    $before = $expression instanceof Exportable
        ? $expression->__get_state()
        : $expression;

    return var_export($before, $return);
}

/**
 * Class Foo
 */
class Foo implements Exportable
{
    private $name = null;
    private $__get_state_called;

    public function __construct($name)
    {
        $this->name = (string)$name;
    }

    /**
     * @see Exportable
     * @return Foo|static
     */
    public function __get_state()
    {
        $before = clone $this; // or if inherited: parent::__get_state()

        $before->__get_state_called = true;

        return $before;
    }
}

$a = 'hello';
my_var_export($a);

echo "\n\n";

$b = new Foo('world');
my_var_export($b);

关于php - 与 __get_state() 之类的 __set_state() 相反?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21762276/

有关php - 与 __get_state() 之类的 __set_state() 相反?的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  3. ruby - Sinatra set cache_control to static files in public folder编译错误 - 2

    我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.

  4. ruby-on-rails - Puma .state 文件 - 2

    我正在尝试使用Capistrano部署带有puma的Rails应用程序。在部署结束时它尝试运行bundleexecpumactl-S/home/deployer/production/shared/sockets/puma.state重启失败了/undefinedmethod`has_key?'forfalse:FalseClass.我只是为puma.state创建了一个空文件。我的问题是这个文件到底是什么,里面应该有什么? 最佳答案 Puma有一个状态文件,记录了进程的PID。如果你是第一次部署,你应该删除.state文件,然后做

  5. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  6. ruby - Arrays Sets 和 SortedSets 在 Ruby 中是如何实现的 - 2

    通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复

  7. ruby-on-rails - 使用 HTTP.get_response 检索 Facebook 访问 token 时出现 Rails EOF 错误 - 2

    我试图在我的网站上实现使用Facebook登录功能,但在尝试从Facebook取回访问token时遇到障碍。这是我的代码:ifparams[:error_reason]=="user_denied"thenflash[:error]="TologinwithFacebook,youmustclick'Allow'toletthesiteaccessyourinformation"redirect_to:loginelsifparams[:code]thentoken_uri=URI.parse("https://graph.facebook.com/oauth/access_token

  8. ruby - what is - gets is a directory - 错误信息 - 2

    我遇到了这个奇怪的错误.../Users/gideon/Documents/ca_ruby/rubytactoe/lib/player.rb:13:in`gets':Isadirectory-spec(Errno::EISDIR)player_spec.rb:require_relative'../spec_helper'#theuniverseisvastandinfinite...itcontainsagame....butnoplayersdescribe"tictactoegame"docontext"theplayerclass"doit"musthaveahumanplay

  9. ruby-on-rails - 尝试设置 Amazon 的 S3 存储桶 : 403 Forbidden error & setting permissions - 2

    我正在关注Hartl的railstutorial.org并已到达11.4.4:Imageuploadinproduction.我做了什么:注册亚马逊网络服务在AmazonIdentityandAccessManagement中,我创建了一个用户。用户创建成功。在AmazonS3中,我创建了一个新存储桶。设置新存储桶的权限:权限:本教程指示“授予上一步创建的用户读写权限”。但是,在存储桶的“权限”下,未提及新用户名。我只能在每个人、经过身份验证的用户、日志传送、我和亚马逊似乎根据我的名字+数字创建的用户名之间进行选择。我已经通过选择经过身份验证的用户并选中了上传/删除和查看权限的框(而不

  10. ruby - 在 ruby​​ 中与 << 相反 - 2

    我正在使用准备一个巨大的字符串循环中的运算符。最后我想删除最后2个字符。some_loopstr我认为上面的最后一个操作也会消耗内存和时间,但我不确定。就是想看看有没有和效果相反的操作所以我可以从同一个字符串中删除最后两个字符。 最佳答案 事实上,字符串切片已经是一种快速且内存高效的操作,因为只有在真正需要时才会复制字符串内容。请参阅“Seeingdouble:howRubysharesstringvalues”中的详细说明。请注意,这是对字符串操作的某种经典优化;Youhaveitinjavatoo我们经常在C中使用类似的技巧。所

随机推荐