Я имею, узнают только что на StackOverflow, что мы можем получить "идентификатор экземпляра" любого ресурса, например:
var_dump(intval(curl_init())); // int(2)
var_dump(intval(finfo_open())); // int(3)
var_dump(intval(curl_init())); // int(4)
var_dump(intval(finfo_open())); // int(5)
var_dump(intval(curl_init())); // int(6)
Я нуждаюсь в чем-то подобном, но обратился к классам:
class foo {
public function __construct() {
ob_start();
var_dump($this); // object(foo)#INSTANCE_ID (0) { }
echo preg_replace('~.+#(\d+).+~s', '$1', ob_get_clean());
}
}
$foo = new foo(); // 1
$foo2 = new foo(); // 2
Вышеупомянутые работы, но я надеялся на более быстрое решение или, по крайней мере, то, которое не включило буферы вывода. Обратите внимание на то, что это будет не обязательно использоваться в конструкторе или даже в самом классе!
spl_object_hash()
не то, что я ищу, потому что два объекта производят идентичные хеши
Вопрос ранее содержал неправильный пример spl_object_hash
вывод; обеспечение, чтобы оба объекта существовали одновременно, производит хеши, которые тонко отличаются:
var_dump(spl_object_hash($foo)); // 0000000079e5f3b60000000042b31773
var_dump(spl_object_hash($foo2)); // 0000000079e5f3b50000000042b31773
Кастинг к интервалу как ресурсы, кажется, не работает на объекты:
Уведомление: Объект нечто класса не мог быть преобразован в интервал.
Существует ли быстрый способ захватить тот же вывод, не используя свойства объектов?
Кроме того, var_dump()
, Я обнаружил методом проб и ошибок это debug_zval_dump()
также производит экземпляр объекта, к сожалению, он также должен произвести буферизацию, так как он не возвращает результат.
spl_object_hash ()
может вам помочь. Он
возвращает уникальный идентификатор объекта
, который всегда одинаков для данного экземпляра.
ИЗМЕНИТЬ после комментария OP:
Вы можете реализовать такое поведение, используя свойство статического класса, например:
class MyClass
{
private static $_initialized = false;
public function __construct()
{
if (!self::$_initialized) {
self::$_initialized = true;
// your run-only-once code
}
}
}
Но на самом деле это не имеет ничего общего с вашим исходным вопросом.
Взгляните на spl_object_hash ()
. Пример использования:
$id = spl_object_hash($object);
Обратите внимание, что для работы вам потребуется PHP 5> = 5.2.0.
У меня нет включенного пакета запуска PECL, чтобы проверить это, но это может позволить вам удалить код конструктора из определения класса после первого создания экземпляра класса. .
Можно ли удалить конструктор из конструктора, было бы интересным экспериментом.
Ну да, с расширением.
Обратите внимание, что дескрипторы, используемые для объектов, которые тем временем были уничтожены, можно использовать повторно.
Сборка с помощью phpize && ./configure && make && make install
#ifndef PHP_EXTTEST_H
# define PHP_EXTTEST_H
# ifdef HAVE_CONFIG_H
# include<config.h>
# endif
# include <php.h>
extern zend_module_entry testext_module_entry;
#define phpext_testext_ptr &testext_module_entry
#endif
#include "testext.h"
PHP_FUNCTION(get_object_id)
{
zval *obj;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj)
== FAILURE) {
return;
}
RETURN_LONG(Z_OBJ_HANDLE_P(obj));
}
static zend_function_entry ext_functions[] = {
PHP_FE(get_object_id, NULL)
{NULL, NULL, NULL, 0, 0}
};
zend_module_entry testext_module_entry = {
STANDARD_MODULE_HEADER,
"testext",
ext_functions, /* Functions */
NULL, /* MINIT */
NULL, /* MSHUTDOWN */
NULL, /* RINIT */
NULL, /* RSHUTDOWN */
NULL, /* MINFO */
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES
};
ZEND_GET_MODULE(testext)
PHP_ARG_ENABLE(testext,
[Whether to enable the "testext" extension],
[ enable-testext Enable "testext" extension support])
if test $PHP_EXTTEST != "no"; then
PHP_SUBST(EXTTEST_SHARED_LIBADD)
PHP_NEW_EXTENSION(testext, testext.c, $ext_shared)
fi
<?php
$a = new stdclass();
$b = new stdclass();
var_dump(get_object_id($a));
var_dump(get_object_id($b));
int(1) int(2)
Пока вы реализуете базовый класс для всех классов, которые вам понадобятся, вы можете сделать что-то вроде этого:
class MyBase
{
protected static $instances = 0;
private $_instanceId = null;
public function getInstanceId()
{
return $this->_instanceId;
}
public function __construct()
{
$this->_instanceId = ++self::$instances;
}
}
class MyTest extends MyBase
{
public function Foo()
{
/* do something really nifty */
}
}
$a = new MyBase();
$b = new MyBase();
$c = new MyTest();
$d = new MyTest();
printf("%d (should be 1) \n", $a->getInstanceId());
printf("%d (should be 2) \n", $b->getInstanceId());
printf("%d (should be 3) \n", $c->getInstanceId());
printf("%d (should be 4) \n", $d->getInstanceId());
Результатом будет:
1 (should be 1) 2 (should be 2) 3 (should be 3) 4 (should be 4)
Если вы не хотите использовать буферизацию вывода ... возможно, используйте var_export
вместо var_dump
?
То, что вы пытаетесь сделать, на самом деле является аспектно-ориентированным программированием (АОП).
На данный момент существует как минимум пара фреймворков для АОП в PHP:
Это может быть излишним для ваших нужд, но вы можете обнаружить, что изучение типа мышления, лежащего в основе подобных идей, приведет вас к кроличьей норе и научит новым способы думать о разработке программного обеспечения в целом - АОП - мощная концепция, позволяющая программировать в терминах стратегий и проблем, или «аспектов».
Такие языки, как PHP, были разработаны для решения задач программирования - концепция APO была разработана для решения задач программиста . Когда обычно вам нужно думать о том, как обеспечить выполнение определенной задачи каждый раз в вашей кодовой базе, вы можете думать об этом как о просто «аспекте» того, как вы программируете, реализовать его напрямую в этих терминах и посчитать о ваших проблемах, которые будут реализованы каждый раз.
Это требует меньшей дисциплины, и вы можете сосредоточиться на решении практических задач программирования, а не пытаться прокладывать свой путь через требования структурного кода высокого уровня.
В любом случае может стоить 5 минут вашего времени; -)
Удачи!