PHP 프로그래밍에서 직렬화 함수는 객체 또는 어레이를 문자열로 변환하는 데 사용되므로 저장 또는 전송이 가능합니다. 그러나 객체를 직렬화 할 때, 다른 객체를 참조하는 객체에 속성이 있고 이러한 객체 사이에 상호 참조 관계가있는 경우 (예 : A는 B를 참조하고 B를 참조 할 수 있음) 무한 재귀를 유발할 수 있으며, 이로 인해 스택 오버 플로가 발생하고 결국 스크립트 충돌로 이어집니다.
이 기사는 PHP의 직렬화 기능을 사용할 때 무한 재귀의 함정을 피하는 방법을 탐구합니다.
PHP의 직렬화 함수는 PHP 값을 저장 또는 전송할 수있는 형식으로 변환합니다. 일반적으로 객체 또는 배열의 지속적인 저장에 사용됩니다. 예를 들어:
<?php
$array = array("name" => "GitBox", "url" => "https://gitbox.net");
$serialized = serialize($array);
echo $serialized;
?>
무한 재귀의 함정은 일반적으로 물체 사이에 원형 기준이있을 때 발생합니다. 예를 들어:
<?php
class Node {
public $name;
public $child;
public function __construct($name) {
$this->name = $name;
}
public function setChild($child) {
$this->child = $child;
}
}
$node1 = new Node("Node 1");
$node2 = new Node("Node 2");
$node1->setChild($node2);
$node2->setChild($node1);
$serialized = serialize($node1); // 이로 인해 무한 재귀가 발생합니다
?>
위의 코드에서 $ node1 및 $ node2는 서로를 참조하십시오. Serialize ($ node1)가 호출되면 PHP는 $ node1 객체를 직렬화하기 시작합니다.이 객체는 Node1 의 자식 속성을 직렬화하고 자식 속성은 $ node2 를 가리 킵니다. 그런 다음 PHP는 $ node2를 계속 시리얼링 한 다음 $ node1 시리얼로 돌아 가서 무한 재귀를 초래하여 메모리 오버플로를 초래할 것입니다.
직렬화를 사용할 때 무한 재귀의 함정에 빠지지 않도록하기 위해 다음 방법을 수행 할 수 있습니다.
PHP는 마법 방법 __sleep을 제공하여 직렬화되어야하는 속성을 지정할 수 있습니다. 객체 속성이 재귀를 일으키는 경우 __sleep 메소드를 사용하여 이러한 속성을 필터링하십시오.
<?php
class Node {
public $name;
public $child;
public function __construct($name) {
$this->name = $name;
}
public function setChild($child) {
$this->child = $child;
}
public function __sleep() {
return ['name']; // 직렬화 전용 $name 재산,원형 참조를 피하십시오
}
}
$node1 = new Node("Node 1");
$node2 = new Node("Node 2");
$node1->setChild($node2);
$node2->setChild($node1);
$serialized = serialize($node1); // 여기에는 재귀가 발생하지 않습니다
echo $serialized;
?>
__sleep 의 속성 목록을 반환하면 어떤 속성이 직렬화 될지 제어 할 수 있으므로 재귀를 피할 수 있습니다.
SploBjectStorage 는 객체를 저장하는 데 특별히 사용되는 클래스이며, 저장시 중복 객체로 인한 재귀 문제를 피할 수 있습니다. 재귀 문제를 피하기 위해 사용할 수 있습니다.
<?php
class Node {
public $name;
public $child;
public function __construct($name) {
$this->name = $name;
}
public function setChild($child) {
$this->child = $child;
}
}
$node1 = new Node("Node 1");
$node2 = new Node("Node 2");
$node1->setChild($node2);
$node2->setChild($node1);
$storage = new SplObjectStorage();
$storage->attach($node1);
$storage->attach($node2);
$serialized = serialize($storage); // 여기에는 재귀가 발생하지 않습니다
echo $serialized;
?>
splobjectStorage는 내부적으로 객체에 대한 참조를 추적하므로 원형 참조로 인한 무한 재귀를 피할 수 있습니다.
경우에 따라 직렬화 된 객체를 복원 할 때 추가 점검을 수행 할 수 있습니다. PHP는 __wakeup Magic 방법을 제공하여 물체를 실시 할 때 일부 작업을 수행 할 수 있습니다.
<?php
class Node {
public $name;
public $child;
public function __construct($name) {
$this->name = $name;
}
public function setChild($child) {
$this->child = $child;
}
public function __wakeup() {
if ($this->child === $this) {
$this->child = null; // 사막화 중 원형 참조를 방지합니다
}
}
}
$node1 = new Node("Node 1");
$node2 = new Node("Node 2");
$node1->setChild($node2);
$node2->setChild($node1);
$serialized = serialize($node1);
echo $serialized;
$unserialized = unserialize($serialized); // 원형 기준은 여기에서 자동으로 지워집니다
?>
__wakeup 방법에서, 우리는 불안정 할 때 재귀를 다시 피하기 위해 루프 기준을 감지하고 지우고 있습니다.
이러한 방법을 통해 PHP 직렬화로 인해 발생할 수있는 무한 재귀 문제를 효과적으로 피할 수있어 객체를 처리 할 때 순환 참조로 인해 프로그램이 충돌하지 않도록합니다. 이 기사가 PHP에서 직렬화 함수를 사용할 때 재귀 트랩을 피하는 방법을 더 잘 이해하는 데 도움이되기를 바랍니다. 질문이 있으시면 계속 논의하십시오!