Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在PHP中建立对象标识

在PHP中建立对象标识
EN

Code Review用户
提问于 2019-06-01 01:08:12
回答 2查看 140关注 0票数 4

我试图在PHP中构建对象标识,以便当我拥有一个对象集合时,每个对象都可以有一个字符串作为标识符,然后所有这些标识符都被组合成一个唯一的md5来表示“集合的标识”。

为什么?这样,当不需要代码时,我可以选择跳过代码的重新执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
interface SomeTestInterface
{
    public function testFunction();
}

abstract class Identifiable
{
    public function __toString()
    {
        $identity_shards = array_merge( get_object_vars( $this ), class_implements( $this ) );

        $identity_string = '';

        foreach( $identity_shards as $identity_shard_key => $identity_shard_value ) {
            $identity_string .= (string) $identity_shard_key . (string) json_encode( $identity_shard_value );
        }

        return md5( get_class( $this ) . $identity_string );
    }
}

class SomeBaseClass extends Identifiable implements SomeTestInterface
{
    public function __construct( $number )
    {
        $this->number = $number;
        $this->thing = 'a';
        $this->other_thing = ['a','b','c',1,2,3,];
    }

    public function testFunction()
    {
        return 'a';
    }
}

这在以下几个方面是可测试的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for( $i = 1; $i < 10000; $i++ ) {
    $class = new SomeBaseClass( $i );
    (string) $class;
}

对于我来说,PHP7.3和WordPress,这需要100 me来执行。

我的微观决定:

  1. 我需要json_encode on $identity_shard_value,因为您不能将数组强制转换为字符串,例如。json_encode在我的经验中速度很快,并且知道如何处理这一切。
  2. 我选择将它变成一个abstract class,因为json_encode无法访问作用域类,因此不能对它找不到的类进行编码,所以我必须能够访问$this,尽管这很奇怪,因为即使在抽象类中,我仍然不能对它进行编码,但我应该能够。

我主要关心的是,我是否真的需要所有这些项目来构建我的对象标识,或者是否有另一种更快的方法。在0.1ms中有10000个物体,虽然它本身很好,但不一定是缩放的。

本质上,在框架的一个模块拥有的集合中实现Identifiable的每个对象都有一个标识,然后我将其组合成一个最终的“集合标识”,以便稍后进行如下检查:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$collection_identity = getCollectionIdentity( $collection ); //MD5 computed from the identity of all these objects

if( $collection_identity != getCollectionIdentityByName( 'some_collection' ) {
    setCollectionIdentity( 'some_collection', $collection_identity );
    //re-execute code
} else {
 retrieveDataFromStorage();
}

如您所见,它检查对象/集合是否有更改,如果是,则重新执行所有其他代码,但如果没有,它只是检索过去生成的“其他代码”,因此,这是一种使用持久存储来跳过重代码执行的方法。

EN

回答 2

Code Review用户

回答已采纳

发布于 2019-06-01 15:05:23

我认为这个代码很好,不能太快。但是..。

MD5散列很可能是唯一的,它毕竟有16^32 (3.4e38)值,但是一旦出现问题,两个不同的对象将具有相同的标识,特别是如果您经常使用它。这可能会在您的软件中引起非常罕见的、随机的错误。几乎不可能追踪到的Bugs。

我不认为__toString()魔术方法是为了达到您现在使用它的目的。我学到了这一点:“你应该总是为了它的目的而使用它。”__toString()的目的是为您提供对象的可读表示。通过现在将其用于标识对象,您将失去以后将其用于其预期目的的能力。

您还依赖于get_object_vars()的一个未记录的属性,即它总是以相同的顺序返回变量。会吗?我不知道。很可能会,但不一定。随着PHP版本的改变,这种情况也可能发生变化,如果发生这种情况,您会感到非常头痛。您可以使用ksort()来确保订单总是相同的,但是这会使事情慢很多。

我还在不同的地方以及手册中的注释中看到,get_object_vars()不返回静态变量。这是有意义的,因为一个类的所有对象都共享这些变量的相同值,但是要记住这一点。

在一些散列集合中,身份散列的存储和检查可能是整个想法中最慢的部分。

然后,my最终问题删除以下代码:

正确编写的代码将知道其对象的标识,或者至少有一个100%可靠的方法来检查它。您的代码应该以这样一种方式编写,即它已经将对象复制降到最低。这段代码的结果似乎是无法编写好而高效的代码(对不起,我在这里试图说明一点)。

例如,许多对象可能已经有一个标识它们的简单ID整数。例如,基于数据库行的模型类很可能具有这样的ID。如果需要,大多数其他类都可以使用类似的方法来标识自己。一旦将这样的ID与类名组合,就应该有一个100%可靠的标识符。

如果您确实需要一种识别各种对象的方法,可以简单地向它们添加一个identity()方法。就像这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
id = $id;
    }   

    public function identity() {
        return get_class() . ":" . $this->id;
    }
}

$myObject = new MyClass(999);

echo $myObject->identity();

?>

这将返回:

MyClass:999

我同意这是一个非常基本的例子,但是对于任何一个类都应该可以做类似的事情。

通过为每个类编写这样一个特定的标识符方法,您可以优化它,这意味着它将更快,并且在任何情况下都可以使它100%可靠。调试也要容易得多,因为您可以看到和阅读正在发生的事情。这里不能藏在神秘的哈希后面。

结论:尽管我反对,但我认为您的代码看起来还不错。然而,我确实怀疑,这种做法最终是否会造成更多的麻烦,这是值得的。

注意:评论中有更多的讨论。最后,酷意面写了对这个问题的答复

票数 4
EN

Code Review用户

发布于 2019-06-02 12:47:19

我最初的问题是:速度和可读性,结果是,使用__toString时遇到了问题。

首先,我最初的方法有一个问题:

如果我的SomeBaseClass在某个时候需要重写它从Identifiable继承的__toString函数,那么我通过同一个SomeBaseClass集合的最初功能就会失败,基本上它不再是Identifiable了,因为这个功能是重写的。

我所做的,基于@KIKO的建议--到目前为止还没有发现bugs -创建了一个继承IdentifiableInterface的接口,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * Interfaces that contains a single method in regards to an object's unique & persistent identity.
 *
 * @internal Mostly used by objects that are inside containers (as such, they're of the same intent, but differ) where comparison between these objects is needed.
 */
interface IdentifiableInterface
{
    /**
     * Retrieves the object's identifier.
     *
     * @internal Do note that this is the object identifier which is meant for identification in the broader scope. You might have a, say, "suggestion identifier" which is specific to the Suggestions Module.
     *
     * @return string
     */
    public function getUniqueObjectIdentifier();
}

然后,在我的作用域(子模块)功能中,我使用表示我集合中的每个对象的SuggestionInterface

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
use Sprout\SproutIdentity\Interfaces\IdentifiableInterface;

interface SuggestionInterface extends IdentifiableInterface
{
}

这基本上使任何SuggestionInterface对象也实现了getUniqueObjectIdentifier,从本质上说,它告诉用户这个对象和类似对象都是在集合中,并且作为集合成员的状态很重要。

虽然我在这里拍拍自己,但我认为这是一种优雅的方式,通过注释和继承(当涉及到接口时,我有点同意这一点),您就可以了解您的系统了。

最后,我是如何从一个助手函数中计算SuggestionInterfaces标识的集合:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static function computeArrayIndetity( $array )
{
    $identity = '';

    foreach( $array as $array_item ) {
        $identity .= $array_item->getUniqueObjectIdentifier();
    }

    return md5( $identity );
}

结果是什么呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
10000 iterations:
new approach - 0.0005820830663045
old approach - 0.0020218133926392

100000 iterations:
new approach - 0.005621083577474 
old approach - 0.019490500291189

当然,这就像把苹果和梨进行比较,当你看到其中一个做什么,另一个做什么,就像“嗯”,但我只是想展示一下,我是如何从一个复杂的、缓慢的方法中走出来的,这个方法本来是很好的,但结果却更优雅、更简单、更快。

虽然速度显然更好,但是新方法创建的副产品并不存在,并且不会因为__toString而出现错误。

它确实要求开发人员设置该函数,因此它违背了自动化的目的,但我将创建一个帮助函数,他们可以使用该函数立即生成名称,而无需考虑它。

票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/221473

复制
相关文章
Activemq获取消费者数量(consumerCount)
最近开始学习activemq系统的使用,关于如何在activemq中时实获取一个主题/队列(topic/queue)的订阅/消费者数量,让我花了挺多时间才搞明白: 在activemq中,可以通过订阅主题或队列对应的消息管理主题,从而获取咨询消息(Advisory Message), 每当新增/减少订阅者时都会收到相关的咨询消息。 Advisory Message中就包含了一些我们想要的数据(包含在consumerCount属性中)。 关于Advisory Message的详细说明参见官方文档: http://activemq.apache.org/advisory-message.html
10km
2020/02/13
2.5K2
ActiveMQ学习之SpringBoot整合ActiveMQ------>主题生产者和消费者
一、pom <!--聚合工程集成关系--> <!--统一整合第三方框架依赖信息--> <parent> <groupId>org.springframework.boot</grou
用户5899361
2020/12/07
3430
ActiveMQ学习之SpringBoot整合ActiveMQ------>队列生产者和消费者
一、pom <!--聚合工程集成关系--> <!--统一整合第三方框架依赖信息--> <parent> <groupId>org.springframework.boot</grou
用户5899361
2020/12/07
5350
ActiveMQ多个消费者消费不均匀问题
如果客户端处理很慢的话,Broker会在之前发送消息的反馈之前,继续发送新的消息到客户端。如果客户端依旧很慢的话,没有得到确认反馈的消息会持续增长。在这种情况下,Broker有可能会停止发送消息给消费者。当未被反馈的消息达到了prefetch limit设置的数字时,Broker将会停止给消费者发送新的消息。除非消费者开始给与反馈,否则得不到任何消息。
java架构师
2019/04/09
1.7K0
ActiveMQ多个消费者消费不均匀问题
activemq之消费者消费解析与高可用策略(三)
有两种方法可以接收消息,一种是使用同步阻塞的MessageConsumer#receive方法。另一种是使用消息监听器MessageListener。这里需要注意的是,在同一个session下,这两者不能同时工作,也就是说不能针对不同消息采用不同的接收方式。否则会抛出异常。
周杰伦本人
2022/10/25
8100
activemq之消费者消费解析与高可用策略(三)
activeMQ
activeMQ 是学习java消息队列的实现项目,使用jfinal + jfinal-ext + activeMQ + quartz快速构建。 1.消息队列 消息队列,其实是一种基于数据结构实现的服务。而java语言中的实现,有apache的activeMQ,比较主流。 2.环境搭建 首先去apache的官网下载apache-activeMQ-...-.zip的包,解压后,运行bin中的activeMQ服务。 在浏览器中输入http://localhost:8186/admin,出现登陆界面输入admin
用户1220053
2018/02/09
9330
activeMQ
activemq学习之activemq功能(一)
消息中间件是值利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。 通过提供消息传递和消息排队模型,可以在分布式架构下扩展进程之间的通信。
周杰伦本人
2022/10/25
1.1K0
activemq学习之activemq功能(一)
ActiveMQ入门
Apache ActiveMQ是当前最流行的开源的,支持多协议的,基于Java的消息中间件,官网的原话是:Apache ActiveMQ™ is the most popular open source, multi-protocol, Java-based messaging server.
CodingDiray
2020/04/24
9711
ActiveMQ入门
ActiveMQ学习总结------Spring整合ActiveMQ 04
注:本文将省略一部分与ActiveMQ无关的spring、mvc等代码,学习者需有SSM框架基础
Arebirth
2020/06/19
5690
ActiveMQ学习之java代码调用ActiveMQ队列
queue:在点对点消息传递域中,目的地被称为队列(一对一)
用户5899361
2020/12/07
6910
ActiveMQ学习之java代码调用ActiveMQ队列
深入讲解ActiveMQ5.X消息的持久性
我经常被问到一些基本的关于解释消息存储在ActiveMQ中是如何工作的问题。在这里我将做一个高层面的解释。注意,上下文环境是它是在JMS范围内。如果你使用的是ActiveMQ的非JMS客户端(e.g.,STOMP,AMQP,MQTT,等),那么它的行为在一些案例中会有所不同。 ActiveMQ JMS的持久性保证对于被标记为“持久的”而不能丢失的消息而言是非常强大的. 让我们看下它在ActiveMQ中是如何被运用的. 主题 主题使用了一个广播机制. 它允许我们在JMS领域使用发布订阅语义模型. 但当我们将一
用户1263954
2018/01/30
7690
深入讲解ActiveMQ5.X消息的持久性
高效协作处理缓存清理需求:生产者-消费者模式助力多模块缓存管理
在现代应用系统中,缓存是提高性能和减少数据库负载的重要手段之一。然而,缓存的数据在某些情况下可能会过期或者变得无效,因此需要及时进行清理。在复杂的应用系统中,可能有多个系统、多个模块产生缓存清理需求,而这些系统、模块之间的清理任务需要高效的协作,以避免数据竞争和资源浪费的问题。
修己xj
2023/08/25
1880
高效协作处理缓存清理需求:生产者-消费者模式助力多模块缓存管理
activeMQ 原
ActiveMQ 消费者接收消息两种方式 1.使用同步方式:消费者会一直等待生产者发送消息或者超市。因其是阻塞式接收消息,故当第一次接收生产者发送过来的消息并消费后,第二次生产者提供的消息不再消费。 2.使用异步监听方式:消费者通过注册监听器,每当生产者有新的消息提供过来是会触发MessageListener的回调方法onMessage()方法。便于后续消息处理。 小结:使用同步方式相当于一次性消费,在实际生产环境中不可能采用这种方式,不至于每次推送数据都重启不服务,不符合实际运用场景,推荐使用注册
wuweixiang
2018/08/14
5230
ActiveMQ详解(1)——ActiveMQ简介与入门程序
ActiveMQ是Apache发布的一款功能强大的消息中间件,它基于JMS 1.1 和 J2EE 1.4规范,目前使用十分广泛。
张申傲
2020/09/03
1.2K0
ActiveMQ 入门
1. 下载 ActiveMQ , 到 activemq 官网上下载 Windows 或者 Linux 对应的安装包
北漂的我
2019/05/29
5350
ActiveMQ介绍
1、ActiveMQ服务器工作模型       通过ActiveMQ消息服务交换消息。消息生产者将消息发送至消息服务,消息消费者则从消息服务接收这些消息。这些消息传送操作是使用一组实现 ActiveMQ应用编程接口 (API) 的对象来执行的。       ActiveMQ客户端使用 ConnectionFactory 对象创建一个连接,向消息服务发送消息以及从消息服务接收消息均是通过此连接来进行。Connection 是客户端与消息服务的活动连接。创建连接时,将分配通信资源以及验证客户端。这是一个相当重要
小帅丶
2018/02/08
1.1K0
初识ActiveMQ
①.消息传递方式介绍: Activemq支持两种方式的消息传递:     广播模式:1-n的方式,是一种发布订阅模式,像腾讯新闻那样,只要我们微信关注了腾讯新闻,那么每个人都会收到推送的新闻     队列模式:1-1的方式,只能有一个消费者端消费生产者生产的数据 ②.消息类型介绍:         Activemq提供了两种消息类型:持久化和非持久化:         消息生产者使用持久(persistent)传递模式发送消息的时候,Producer.send() 方法会被阻塞,直到 broker 发送一个
用户1215919
2018/02/27
2.1K0
安装ActiveMQ
接着进入到与系统位数对应的目录下,使用管理员身份运行activemq.bat,就可以直接启动了:
端碗吹水
2020/09/23
7460
安装ActiveMQ
ActiveMQ学习之linux下ActiveMQ环境搭建
https://activemq.apache.org/components/classic/download/
用户5899361
2020/12/07
6180
ActiveMQ学习之linux下ActiveMQ环境搭建
ActiveMQ学习之java代码调用ActiveMQ主题
queue:在点对点消息传递域中,目的地被称为队列(一对一)
用户5899361
2020/12/07
4090
ActiveMQ学习之java代码调用ActiveMQ主题

相似问题

ASIHTTPRequest似乎总是缓存JSON数据

20

芭乐缓存'expireAfterWrite‘似乎并不总是有效

14

ActiveMQ:慢速处理消费者

12

ActiveMQ -平衡消费者人数

11

当我不想让FireFox缓存表单时,它似乎总是缓存它

24
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文