是否有一种更原生的方式(例如内置函数)使用更少的用户空间代码来检查对象属性值是否已更改而不是使用其中一种方法:
序列化方法
$obj = new stdClass(); // May be an instance of any class
echo $hashOld = md5(serialize($obj)) . PHP_EOL;
$obj->change = true;
echo $hashNew = md5(serialize($obj)) . PHP_EOL;
echo 'Changed: '; var_dump($hashOld !== $hashNew);
结果是:
f7827bf44040a444ac855cd67adfb502 (initial)
506d1a0d96af3b9920a31ecfaca7fd26 (changed)
Changed: bool(true)
卷影复制方法
$obj = new stdClass();
$shadowObj = clone $obj;
$obj->change = true;
var_dump($shadowObj != $obj);
结果是:
bool(true);
这两种方法都有效。但与非用户态实现相比,两者都有缺点。第一个需要 CPU 进行序列化和散列,第二个需要内存来存储克隆。有些类可能无法克隆。
PHP 不会跟踪对象属性的变化吗?难道 PHP 没有公开使用它的方法吗?
最佳答案
你想做什么?
您正在尝试将对象与自身进行比较,经过一些“未知”操作链以检查对象是否已更改。如果这是真的,那么有一些逻辑点需要观察。首先,如果您想将对象与自身进行比较,您只有两个选择:
没有其他合乎逻辑的方法。比较内存分配、真实对象、复制对象、比较哈希,都是第一点。跟踪更改,在对象内保存更改,记住同时操作,在第 2 点内。
所以在我看来,这个问题有点像备份数据问题。在那种情况下,有很多很多解决方案,但据我所知,没有一个是在 php 中硬编码的。为什么?
答案很简单。 PHP 人员遇到了与您遇到的问题相同的问题:)。 因为如果这将在 php 中进行硬编码,那么 php 应该运行/使用这些机制 (1) 或 (2) 中的一种。
在那种情况下,您创建的每个对象以及您进行的每个操作都应该写在某个地方以记住每个状态/对象/某物,并在将来使用它们进行比较。
虽然您需要此解决方案,但几乎 ~100% 的网站不需要。因此,在 php 中对其进行硬编码会使 ~100% 的网站运行速度变慢,而您的工作速度加快 ;)。
我能想到的唯一解决方案(将来可能内置在 php 中)是制作某种 php 配置标志:track objects,并且仅当此标志为 true,然后运行所有跟踪对象状态的 php 机制。 但这也意味着巨大的性能差距。因为所有的ifs(if tracking, if tracking, if tracking)也会消耗处理器和内存时间。
还有一个问题,比较什么?你需要比较对象和同一个对象,但是......几分钟前?几手术前?不......你必须在代码中指向一个地方,然后在代码中指向第二个地方并比较这两个地方的对象。 所以假设的自动跟踪是......有点无能为力,因为在时间对象状态数组中没有“键”。我的意思是,即使你有magic_object_comparer 函数,它应该是什么样子?
<?php
function magic_object_comparer() {} // Arguments??
function magic_object_comparer($object_before, $object_after) {} // you must save object_before somewhere...??
function magic_object_comparer($object, $miliseconds) {} // How many miliseconds?
function magic_object_comparer($object, $operations) {} // How many operations? Which operations?
magic_comparer_start($object);
// ... Few operations...
$boolean = magic_comparer_compare_from start($object);
// Same as own implementation...
?>
毕竟,我建议为此实现某种自己的机制,并且记住只在需要的地方使用它。因为这种机制肯定会耗费时间和内存。所以仔细想想:
在所有这些之后,尝试实现它。我看到您拥有丰富的 PHP 知识,所以我很确定您会想出一些办法。 在这个问题和讨论中也有很多评论和可能的想法。
但毕竟也许我解释了一点为什么,没有内置解决方案,以及为什么将来不应该有一个......:)。
看这里:http://www.fluffycat.com/PHP-Design-Patterns/ .这是关于 php 模式的重要资源。您应该查看 adapter、decorator 和 observer 模式,以获得可能的优雅的面向对象解决方案。
关于php - 检查对象是否已更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28691224/
如何正确创建Rails迁移,以便将表更改为MySQL中的MyISAM?目前是InnoDB。运行原始执行语句会更改表,但它不会更新db/schema.rb,因此当在测试环境中重新创建表时,它会返回到InnoDB并且我的全文搜索失败。我如何着手更改/添加迁移,以便将现有表修改为MyISAM并更新schema.rb,以便我的数据库和相应的测试数据库得到相应更新? 最佳答案 我没有找到执行此操作的好方法。您可以像有人建议的那样更改您的schema.rb,然后运行:rakedb:schema:load,但是,这将覆盖您的数据。我的做法是(假设
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe
假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。
我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的
我最喜欢的Google文档功能之一是它会在我工作时不断自动保存我的文档版本。这意味着即使我在进行关键更改之前忘记在某个点进行保存,也很有可能会自动创建一个保存点。至少,我可以将文档恢复到错误更改之前的状态,并从该点继续工作。对于在MacOS(或UNIX)上运行的Ruby编码器,是否有具有等效功能的工具?例如,一个工具会每隔几分钟自动将Gitcheckin我的本地存储库以获取我正在处理的文件。也许我有点偏执,但这点小保险可以让我在日常工作中安心。 最佳答案 虚拟机有些人可能讨厌我对此的回应,但我在编码时经常使用VIM,它具有自动保存功
我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO
我正在使用Watir运行一个Ruby脚本来为我自动化一些事情。我试图自动将一些文件保存到某个目录。因此,在我的Mozilla设置中,我将默认下载目录设置为桌面并选择自动保存文件。但是,当我开始运行我的脚本时,这些更改并没有反射(reflect)出来。似乎首选项恢复为默认值。我已经包括以下内容require"rubygems"#Optional.require"watir-webdriver"#Forwebautomation.require"win32ole"#Forfilesavedialog.并打开一个新的firefox实例:browser=Watir::Browser.new(:
我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的
我在使用Ruby1.9.2p290更改文本文件的编码时遇到问题。我收到错误消息invalidbytesequenceinUTF-8(ArgumentError)。问题(我认为)在于字符集似乎是未知的。如果我执行以下操作,则从命令行:$filetest.txt我得到:Non-ISOextended-ASCIIEnglishtext,withCRLFlineterminators或者,或者,如果我这样做:$file-itest.txt我得到:test.txt:text/plain;charset=unknown但是,如果我这样做,在Ruby中:data=File.open("test.tx