PHP에서 Serialize () 함수는 객체 또는 배열을 저장 또는 전송을 위해 문자열로 변환하는 데 사용됩니다. 그러나 객체에 재귀 참조가 포함되어있을 때 Serialize () 함수는 문제가 발생할 수 있습니다 (즉, 객체 참조 자체 또는 서로 참조). 이 기사는 Serialize () 함수를 사용하여 재귀 참조와 함께 복잡한 객체 직렬화 문제를 처리하고 관련 솔루션을 제공하는 방법에 대해 논의합니다.
재귀 참조는 그 자체에 대한 참조를 포함하는 객체의 속성을 나타내거나 서로를 참조하는 여러 객체 사이에 관계가 있습니다. 이 상황은 복잡한 데이터 구조, 특히 트리 구조 및 그래프 구조와 같은 데이터 모델에서 더 일반적입니다. 예를 들어, 자식 객체가 포함 된 부모 객체가 있다고 가정하고 Child Object에 부모 객체에 대한 참조가 포함되어 있으므로이 구조에는 재귀 참조 문제가 발생할 수 있습니다.
PHP에서 Serialize () 함수는 PHP 변수를 문자열로 변환하는 표준 방법입니다. 그러나 객체 내부에 재귀 참조가있을 때 Serialize ()는 동일한 객체를 지속적으로 직렬화하려고 시도하여 스택 오버플로 또는 무한 재귀를 초래하기 때문에 죽은 루프에 빠지게됩니다. 다음은 재귀 참조가있는 사례를 보여주는 간단한 예입니다.
class Node {
public $value;
public $next;
public function __construct($value) {
$this->value = $value;
}
}
$node1 = new Node(1);
$node2 = new Node(2);
$node3 = new Node(3);
$node1->next = $node2;
$node2->next = $node3;
$node3->next = $node1; // 재귀 참조
echo serialize($node1);
위의 코드에서 $ node1 , $ node2 및 $ node3는 서로를 참조하여 루프를 형성합니다. Serialize ()가 호출되면 PHP는 무한 재귀 상태로 들어가 오류가 발생합니다.
재귀 참조 문제를 해결하기 위해 몇 가지 방법을 채택 할 수 있습니다. 가장 일반적인 두 가지 방법은 Serialize () 의 사용자 정의 프로세서를 사용하거나 PHP의 __sleep () 및 __wakeup () 마법 방법을 사용하여 객체의 직렬화 프로세스를 제어하는 것입니다.
__sleep () 메소드는 객체가 직렬화되기 전에 객체의 속성을 처리 할 수 있으며, __wakeup () 메소드는 객체가 사막화 될 때 물체의 상태를 복원합니다. 이 방법을 사용하여 재귀 참조로 인한 문제를 방지 할 수 있습니다.
class Node {
public $value;
public $next;
public function __construct($value) {
$this->value = $value;
}
public function __sleep() {
// 여기에서 필요한 속성 만 직렬화하도록 선택할 수 있습니다.,避免재귀 참조
return ['value'];
}
public function __wakeup() {
// 사막화 동안의 운영,객체 간의 관계를 다시 설정할 수 있습니다
}
}
$node1 = new Node(1);
$node2 = new Node(2);
$node3 = new Node(3);
$node1->next = $node2;
$node2->next = $node3;
$node3->next = $node1; // 재귀 참조
echo serialize($node1);
이 예에서 __sleep () 메소드는 값 속성 만 반환하여 직렬화 프로세스 중에 속성 만 저장되도록 재귀 참조 문제를 피합니다.
또 다른 접근법은 재귀 참조를 수동으로 처리하는 것인데, 이는 이미 직렬화 된 객체를 기록하기 위해 글로벌 배열을 사용하여 기록 할 수 있습니다. 이를 통해 직렬화 중에 이미 처리 된 객체를 건너 뛸 수 있으므로 무한 재귀 문제를 피할 수 있습니다. 이 방법은 복잡한 물체 구조에서 잘 사용할 수 있습니다.
class Node {
public $value;
public $next;
public function __construct($value) {
$this->value = $value;
}
}
$visited = [];
function safe_serialize($obj) {
global $visited;
if (in_array(spl_object_hash($obj), $visited)) {
return ''; // 중복 직렬화를 피하십시오
}
$visited[] = spl_object_hash($obj);
return serialize($obj);
}
$node1 = new Node(1);
$node2 = new Node(2);
$node3 = new Node(3);
$node1->next = $node2;
$node2->next = $node3;
$node3->next = $node1; // 재귀 참조
echo safe_serialize($node1);
이 예에서는 이미 직렬화 된 객체의 식별자를 저장하기 위해 Global $를 사용하여 ( SPL_OBJECT_HASH () 를 통해 얻음). 객체가 직렬화 된 경우, 재귀 참조 문제를 피하기 위해 객체를 건너 뛰십시오.
재귀 참조와 함께 복잡한 객체 직렬화 문제를 처리하려면 PHP의 내장 __sleep () 및 __wakeup () 마법 메소드를 통해 직렬화를 사용자 정의하거나 반복적 인 직렬화를 피하기 위해 직렬화 프로세스를 수동으로 구현할 수 있습니다. 다양한 요구 사항과 객체 구조의 경우 재귀 참조로 인한 죽은 루프 또는 스택 오버플로 오류를 피하기 위해 다른 방법을 선택할 수 있습니다.