class array - الحصول على معرف مثيل كائن في PHP




variables (9)

ليس لدي تمكين PECL runkit لاختبار هذا ، ولكن هذا قد يسمح لك بإزالة رمز منشئ من تعريف الفئة بعد المرة الأولى التي تم إنشاء مثيل للفئة.

ما إذا كان يمكنك إزالة المنشئ من داخل منشئ ستكون تجربة مثيرة للاهتمام.

لقد تعلمت منذ قليل على أنه يمكننا الحصول على "معرف المثيل" لأي مورد ، على سبيل المثال:

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

يبدو أن التمثيل إلى الموارد مثل الموارد لا يعمل مع الكائنات:

إشعار: لا يمكن تحويل كائن فئة foo إلى int.

هل هناك طريقة سريعة للاستيلاء على نفس الإخراج دون استخدام خصائص الكائن ؟

إلى جانب var_dump() ، لقد اكتشفت عن طريق التجربة والخطأ أن debug_zval_dump() يخرج أيضًا مثيل الكائن ، وللأسف فإنه يحتاج أيضًا إلى تخزين مؤقت لأنه لا يعيد النتيجة.


أليكس ، كان الحل الخاص بك في السؤال هو بالضبط ما احتاجه ، ولكن في الواقع يكسر عندما يكون هناك كائن في كائن ، يقوم بإرجاع # آخر في var_dump. لقد أصلحت هذا ، وجعلت regex أسرع ، ووضعها في وظيفة صغيرة لطيفة.

/**
 * Get global object ID
 * From: http://.com/questions/2872366/get-instance-id-of-an-object-in-php
 * By: Alix Axel, non-greedy fix by Nate Ferrero
 */
function get_object_id(&$obj) {
    if(!is_object($obj))
        return false;
    ob_start();
    var_dump($obj);// object(foo)#INSTANCE_ID (0) { }
    preg_match('~^.+?#(\d+)~s', ob_get_clean(), $oid);
    return $oid[1]; 
}

spl_object_hash() قد يساعدك هنا. هذا

بإرجاع معرف فريد للكائن

وهو دائمًا نفس الشيء بالنسبة إلى مثيل معين.

تعديل بعد تعليق OP:

يمكنك تنفيذ مثل هذا السلوك باستخدام خاصية فئة ثابتة ، على سبيل المثال:

class MyClass 
{
    private static $_initialized = false;

    public function __construct()
    {
        if (!self::$_initialized) {
            self::$_initialized = true;
            // your run-only-once code 
        }
    }
}

ولكن في الواقع هذا ليس له علاقة بسؤالك الأصلي.


ما دمت تقوم بتطبيق الفئة الأساسية على جميع الفئات التي ستحتاج إليها ، يمكنك فعل شيء كالتالي:

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) 

إلقاء نظرة على spl_object_hash() . مثال على الاستخدام:

$id = spl_object_hash($object);

لاحظ أنك ستحتاج إلى PHP 5> = 5.2.0 للقيام بذلك.


حسنا ، نعم ، مع التمديد.

لاحظ أنه يمكن إعادة استخدام المقابض المستخدمة للعناصر التي تم تدميرها في الوقت الحالي.

بناء مع phpize && ./configure && make && make install

testext.h

#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

testext.c

#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)

config.m4

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)

إذا كنت لا ترغب في استخدام التخزين المؤقت للإخراج ... ربما استخدم var_export بدلاً من var_dump ؟


هذا متأخر قليلاً إلى الطرف ولكن لم أتمكن من رؤية هذه الإجابة وتم مؤخراً تطبيق شيء مماثل لفئة التصحيح (لمعالجة المراجع الدائرية). نظرًا لأنك قد تعرف أو لا تعرف وظائف الطباعة العادية مثل var_export ، يكون دعم المرجع var_export محدودًا أو لا.

كما لوحظ spl_object_hash فريد لكل مثيل ، فإن المشكلة التي واجهتها هي أنها قبيحة. لا تتناسب بالفعل مع طباعة مصحح الأخطاء الخاص بي لأنه شيء مثل هذا 000000006ac56bae0000000044fda36f الذي يمكن أن يكون من الصعب مقارنته ليقول هذا 000000006ac56bae0000000044fda35f . ﻟذا ، ﻓﺎﻟﺻﯾﻐﺔ اﻟﻣؤﻗﺗﺔ ﺻرﺣت ﻣﺎ أردت ﻓﯾﮫ ﻓﻘط ﻋددًا ﻣن اﻟﻣﺛﺎل (ﻟﻘد ﻛﻧت أﺣﺗﺎج ﻓﻘط ﻟﮭذا ﻋﻠﻰ أﺳﺎس ﻛل ﻓﺻل).

لذلك كان الحل البسيط بالنسبة لي هو القيام بما يلي.

    $class = get_class( $input );
    $hash = spl_object_hash( $input );
    if( !isset( $objInstances[ $class ] )){
        $objInstances[ $class ] = array();
    }

    $output = 'object(%s) #%s (%s){%s}'; //class, instance, prop_count, props
    if( false === ( $index = array_search($hash, $objInstances[ $class ] ) ) ){
        $index = count($objInstances[ $class ]); //set init index for instance
        $objInstances[ $class ][] = $hash;
        // .... debugging code
        $output = 'debugging result.', //sprintf 
    }else{
        $output = sprintf( $output, $class, $index, 0, '#_CIRCULAR_REFRENCE_#');
    }

من الواضح أن شفرة التصحيح أكثر تعقيدًا ، لكن الشيء الأساسي هنا هو أنه من خلال تتبع الطبقة وتجزئة التجزئة في $objInstances يمكنني بسهولة تعيين أرقام مثيل الخاصة بي خارج الفصل الدراسي. هذا يعني أنني لست بحاجة إلى بعض الإختراق القبيح (الذي يؤثر على رمز الفصل) للحصول على رقم مرجعي. أيضا ، لست بحاجة إلى عرض تجزئة spl "قبيحة". على أي حال رمز بلدي الكامل لهذا المخرجات شيء من هذا القبيل.

$obj = new TestObj();
$obj1 = new TestObj();

$obj->setProProp($obj1);
$obj1->setProProp($obj); //create a circular reference 

object(TestObj) #0 (7){
    ["SOME_CONST":const] => string(10) 'some_const',
    ["SOMEOTHER_CONST":const] => string(16) 'some_other_const',
    ["SOME_STATIC":public static] => string(6) 'static',
    ["_PRO_STATIC":protected static] => string(10) 'pro_static',
    ["someProp":public] => string(8) 'someProp',
    ["_pro_prop":protected] => object(TestObj) #1 (7){
        ["SOME_CONST":const] => string(10) 'some_const',
        ["SOMEOTHER_CONST":const] => string(16) 'some_other_const',
        ["SOME_STATIC":public static] => string(6) 'static',
        ["_PRO_STATIC":protected static] => string(10) 'pro_static',
        ["someProp":public] => string(8) 'someProp',
        ["_pro_prop":protected] => object(TestObj) #0 (0){#_CIRCULAR_REFRENCE_#},
        ["_proProp":protected] => string(7) 'proProp'
    },
    ["_proProp":protected] => string(7) 'proProp'
}

كما ترى ، من السهل جدًا معرفة مكان object(TestObj) #0 (0){#_CIRCULAR_REFRENCE_#} من الآن. كنت أرغب في الحفاظ على رمز التصحيح هذا على مقربة من var_dump الأصلي الذي يخرج هذا.

object(TestObj)#7 (3) {
  ["someProp"]=> string(8) "someProp"
  ["_pro_prop":protected]=> object(TestObj)#10 (3) {
    ["someProp"]=> string(8) "someProp"
    ["_pro_prop":protected]=> *RECURSION*
    ["_proProp":protected]=> string(7) "proProp"
  }
  ["_proProp":protected]=> string(7) "proProp"
}

الفرق هنا هو أنني أحتاج إلى العودة كسلسلة ، وليس الإخراج إلى المتصفح. كما أردت أيضًا أن أتمكن من إظهار ثوابت الصفوف والخصائص الثابتة والخصائص الخاصة (مع استخدام العلامات لتغيير مخرجات المصحح وحد العمق). وأردت الحصول على مزيد من المعلومات حول ما هو المرجع الدائري بدلاً من *RECURSION* الذي لا يخبرني بأي شيء.

آمل أن يساعد شخص ما في المستقبل.

في ما يلي التعليمة البرمجية الكاملة للفئة Debug ، يمكنك العثور على هذا المستخدم حول السطر # 300

https://github.com/ArtisticPhoenix/Evo/blob/master/Evo/Debug.php


فقط لأنني لم أر AngularJS المذكورة ، ويعتقد أن الناس قد ترغب في معرفة ...

angular.copy يوفر أيضًا طريقة للنسخ العميق للأجسام والمصفوفات.





php class object resources instance