후드 아래의 PHP 변수

PHP의 변수는 변수의 유형, 값, 이 컨테이너에 대한 참조 변수의 양 및 플래그(이 변수가 참조되는지 여부)를 저장하는 일부 컨테이너입니다.



구조체와 포인터



구조는 클래스와 매우 유사하지만 메서드, 데이터, 데이터에 대한 포인터 및 함수에 대한 포인터만 가질 수 없습니다. C에서 구조를 선언하면 데이터 유형을 정의합니다. 그리고 변수를 정의할 때 다음과 같이 해당 변수의 유형 대신 이 구조의 이름을 작성할 수 있습니다.

my_super_struct super_struct_instance;

포인터는 변수와 비슷하지만 그 값은 메모리에 주소를 저장합니다. 참조 변수는 역참조 포인터처럼 작동합니다. 즉, 포인터 값에 액세스합니다. 예를 살펴보겠습니다.

// defining pointer `foo`, that will points to the variable with `int` type
int *foo;
// defining variable with `int` type
int bar = 3;

// taking reference to variable `bar` and assigning it to pointer.
// `foo` stores memory address, where `bar` stores
foo = &bar;

// with an asterisk we dereference the pointer (take the value at its address) and increment the value
(*foo)++;

// we increment the pointer itself, that means the pointer will refer at another value
foo++;



컨테이너



컨테이너는 zval("Zend 값"의 줄임말)라는 구조로, 임의의 PHP 값을 나타내며 다음과 같이 보입니다.

struct zval {
    zvalue_value value;
    zend_uchar type;
    zend_uchar is_ref;
    zend_ushort refcount;
};

보시다시피 값, 유형, 플래그 및 참조 변수의 양이 있습니다. PHPzval는 다음 8가지 유형을 지원합니다.
  • BOOL
  • LONG (부호 있는 정수 유형)
  • DOUBLE (부동 소수점 숫자를 저장하는 데 사용됨)
  • STRING
  • ARRAY
  • OBJECT
  • RESOURCE
  • NULL
  • zvalue_valueunion입니다. 공용체는 서로 다른 형식의 멤버 선언이 여러 개 있을 수 있지만 하나만 사용되는 특수 형식입니다. 다음과 같이 정의합니다.

    typedef union _zvalue_value {
        long lval; // integer
        double dval; // float
        struct {
            char *val;
            int len;
        } str; // string
        HashTable *ht; // array
        zend_object obj; // object
    } zvalue_value;
    

    결과적으로 이 유형의 변수를 생성하면 정확히 공용체의 가장 무거운 요소를 차지하는 만큼 메모리를 차지하게 됩니다.



    이 모든 것이 필요한 이유



    먼저 refcount가 필요한 이유를 알아봅시다. 그것은 매우 간단합니다. 다른 변수의 변수 값에 할당할 때 둘 다 하나의 zvalrefcount 증분을 참조합니다.



    이제 이러한 변수 중 하나의 값을 변경하면 PHP는 1보다 큰 refcount를 보고 이 zval를 복사하고 거기에서 변경하며 변수는 이미 새로운 zval를 가리킵니다. 다음과 같이 표시됩니다.


    PHP
    후드




    $foo = "baz";
    $bar = $foo;
    


    bar,foo: {
        type: string,
        value:
            str:
                val: "baz"
                len: 3
        is_ref: 0
        refcount: 2
    }
    




    $bar .= "q";
    


    foo: {
        type: string,
        value:
            str:
                val: "baz"
                len: 3
        is_ref: 0
        refcount: 1
    }
    bar: {
        type: string,
        value:
            str:
                val: "bazq"
                len: 4
        is_ref: 0
        refcount: 1
    }
    



    이 기술을 "기록 중 복사"라고 하며 메모리 소비를 상당히 줄일 수 있습니다. 또한 refcount는 메모리에서 zval를 갖는 모든 refcount = 0를 제거하는 가비지 수집기에 필요합니다.

    참조는 어떻게 됩니까? 그리고 is_ref가 작동합니까? 매우 간단합니다. 변수에서 참조를 생성하면 is_ref 플래그가 1이 되고 이 zval에 대한 위의 최적화가 적용되지 않습니다.


    PHP
    후드




    $foo = "baz";
    $bar = $foo;


    bar,foo: {
        type: string,
        value:
            str:
                val: "baz"
                len: 3
        is_ref: 0
        refcount: 2
    }
    




    $baz = &$foo;


    baz,foo: {
        type: string,
        value:
            str:
                val: "baz"
                len: 3
        is_ref: 1
        refcount: 2
    }
    bar: { // variable `bar` was allocated to a separate `zval`
        type: string,
        value:
            str:
                val: "baz"
                len: 3
        is_ref: 0
        refcount: 1
    }
    




    $qwe = $foo;


    baz,foo: {
        type: string,
        value:
            str:
                val: "baz"
                len: 3
        is_ref: 1
        refcount: 2
    }
    bar: {
        type: string,
        value:
            str:
                val: "baz"
                len: 3
        is_ref: 0
        refcount: 1
    }
    // this variable was also allocated to a separate `zval`
    qwe: {
        type: string,
        value:
            str:
                val: "baz"
                len: 3
        is_ref: 0
        refcount: 1
    }
    





    Interesting in reading more about PHP? Follow this link to find more articles 😉

    좋은 웹페이지 즐겨찾기