php5 대상 복제,clone,얕은 복제와 깊은 복제 실례 설명
객체 복제의 유래
왜 대상에게'복제'라는 개념이 있는지, 이것은 PHP5에서 대상의 값 전달 방식과 밀접한 관계를 가진다. 아래의 간단한 코드를 살펴보자.
PHP 코드
/**
*
*/
class Television
{
/**
*/
protected $_screenLength = 300;
/**
*/
protected $_screenHight = 200;
/**
*/
protected $_color = 'black';
/**
*/
public function getColor()
{
return $this->_color;
}
/**
*/
public function setColor($color)
{
$this->_color = (string)$color;
return $this;
}
}
$tv1 = new Television();
$tv2 = $tv1;
이 코드는 텔레비전의 종류인 텔레비젼을 정의합니다. $tv1은 텔레비전의 실례입니다. 그리고 우리는 일반적인 변수에 따라 $tv1의 값을 $t2에 부여합니다.그럼 이제 우리는 텔레비전 두 대를 가지고 있다. $tv1과 $tv2가 있다. 정말 그런가?우리 한번 테스트해 봅시다.
PHP 코드
echo 'color of tv1 is: ' . $tv1->getColor();//tv1 black
echo '
';
echo 'color of tv2 is: ' . $tv2->getColor();//tv2 black
echo '
';
// tv2
$tv2->setColor('white');
echo 'color of tv2 is: ' . $tv2->getColor();//tv2 white
echo '
';
echo 'color of tv1 is: ' . $tv1->getColor();//tv1 white
먼저 tv1과 tv2의 색깔이 모두 Black인 것을 보았습니다. 지금은 tv2의 색깔을 바꾸기를 원합니다. 그래서 우리는 그 색깔을 화이트로 설정했습니다. tv2의 색깔을 다시 보니 화이트가 된 것 같습니다. 우리의 요구를 충족시킨 것 같지만 생각보다 순조롭지 않습니다. tv1의 색깔을 이어서 보았을 때 tv1도 Black에서 화이트가 된 것을 발견했습니다.우리는 tv1의 색깔을 다시 설정하지 않았는데, 왜 tv1이 블랙을 다시 화이트로 바뀌었을까?이는 PHP5에서 객체에 대한 지정과 전송 값이 모두 참조로 지정되기 때문입니다.PHP5는 Zend 엔진 II를 사용하며 객체는 다른 일반 변수처럼 Zval에 저장되지 않고 독립된 구조의 Object Store에 저장됩니다(PHP4에서 객체는 일반 변수와 마찬가지로 Zval에 저장됩니다).컨텐트(value)가 아닌 객체의 포인터만 Zval에 저장됩니다.우리가 하나의 대상을 복제하거나 하나의 대상을 매개 변수로 함수에 전달할 때, 우리는 데이터를 복제할 필요가 없다.동일한 객체 포인터만 유지하고 현재 특정 객체가 가리키는 Object Store를 다른 zval에서 알립니다.객체 자체가 Object Store에 있기 때문에, 우리가 그것에 대한 어떠한 변화도 이 대상 포인터를 가진 모든 zval 구조에 영향을 미칠 것이다. 프로그램에서 목표 대상의 어떠한 변화도 원본 대상에게 영향을 미칠 것이다.이렇게 하면 PHP 객체가 항상 참조(reference)로 전달되는 것처럼 보입니다.그래서 이상의 tv2와 tv1은 사실 같은 텔레비전을 가리키는 실례이다. 우리가 tv1 또는 tv2에 대한 조작은 모두 이 같은 실례를 겨냥한 것이다.그래서 우리의 복제는 실패했다.보아하니 직접 변수의 값을 부여하는 방식은 대상을 복사할 수 없는 것 같다. 이를 위해 PHP5는 대상을 복제하는 전문적인 조작, 즉 clone을 제공한다.이것이 바로 대상 복제의 유래다.
클론으로 객체 복사
이제 PHP5의 clone 언어 구조를 사용하여 객체를 복사합니다. 코드는 다음과 같습니다.
PHP 코드
$tv1 = new Television();
$tv2 = clone $tv1;
echo 'color of tv1 is: ' . $tv1->getColor();//tv1 black
echo '
';
echo 'color of tv2 is: ' . $tv2->getColor();//tv2 black
echo '
';
// tv2
$tv2->setColor('white');
echo 'color of tv2 is: ' . $tv2->getColor();//tv2 white
echo '
';
echo 'color of tv1 is: ' . $tv1->getColor();//tv1 black
이 코드의 두 번째 줄에서 우리는 clone 키워드로 tv1을 복제했다. 현재 우리는 진정한 tv1의 복사 tv2를 가지고 있다. 우리는 이전의 방법에 따라 복제가 성공했는지 검사한다.우리는 tv2의 색깔을 화이트, tv1의 색깔로 바꿨는지 블랙으로 바꿨는지 알 수 있다. 그러면 우리의 복제 작업은 성공할 것이다.
__clone 마술 방법
현재 우리는 이러한 상황을 고려하여 모든 텔레비전은 자신의 번호를 가지고 있어야 한다. 이 번호는 우리의 신분증 번호처럼 유일해야 한다. 그래서 우리가 텔레비전을 복제할 때, 우리는 이 번호도 복제되어 번거로움을 초래하지 않기를 원하지 않는다.우리가 생각한 전략 중 하나는 값을 매긴 텔레비전의 번호를 비운 다음에 필요에 따라 번호를 다시 분배하는 것이다.
그렇다면clone 마술 방법은 이런 문제를 전문적으로 해결하는 데 쓰인다.clone 마술 방법은 대상이 복제될 때 터치됩니다.우리는 텔레비전 종류의 Television 코드를 수정하고 번호 속성과 를 추가했다clone 방법, 코드는 다음과 같습니다.
PHP 코드
/**
*/
class Television
{
/**
*/
protected $_identity = 0;
/**
*/
protected $_screenLength = 300;
/**
*/
protected $_screenHight = 200;
/**
*/
protected $_color = 'black';
/**
*/
public function getColor()
{
return $this->_color;
}
/**
*/
public function setColor($color)
{
$this->_color = (string)$color;
return $this;
}
/**
*/
public function getIdentity()
{
return $this->_identity;
}
/**
*/
public function setIdentity($id)
{
$this->_identity = (int)$id;
return $this;
}
public function __clone()
{
$this->setIdentity(0);
}
}
다음은 우리가 이런 텔레비전의 대상을 복제할 것이다.
PHP 코드
$tv1 = new Television();
$tv1->setIdentity('111111');
echo 'id of tv1 is ' . $tv1->getIdentity();//111111
echo '
';
$tv2 = clone $tv1;
echo 'id of tv2 is ' . $tv2->getIdentity();//0
우리는 텔레비전 tv1을 생산했고, 그것의 번호를 111111로 설정했다. 그리고 우리는 clone으로 tv1을 tv2로 복제했다. 이때clone 마술 방법이 촉발되었습니다. 이 방법은 직접 작용하고 복제된 대상 tv2입니다.clone 방법에서 setIdentity 구성원 방법을 호출하여 tv2의identity 속성을 비워서 다음에 다시 번호를 매길 수 있도록 합니다.이로써 우리는 을 볼 수 있다clone 마술 방법은 clone 대상이 될 때 추가 조작을 하는 데 매우 편리하게 할 수 있다.
clone 조작의 치명적인 결함
clone은 정말 이상적인 복제 효과에 도달할 수 있습니까?어떤 경우, 클론 조작이 우리가 상상했던 것만큼 완벽하지 않다는 것을 알게 될 것이다.우리는 이상의 텔레비전 종류를 수정한 후에 테스트를 할 것이다.
텔레비전마다 리모컨이 하나씩 붙어 있기 때문에 우리는 리모컨 종류가 하나 있을 것이다. 리모컨과 텔레비전은 일종의'집합'관계(상대적으로'조합'관계이고 약한 의존 관계이다. 왜냐하면 일반적인 상황에서 텔레비전은 리모컨이 없어도 자주 사용할 수 있기 때문이다). 현재 우리의 텔레비전 대상은 모두 리모컨 대상에 대한 인용을 가지고 있어야 한다.다음은 코드를 볼게요.
PHP 코드
/**
*/
class Television
{
/**
*/
protected $_identity = 0;
/**
*/
protected $_screenLength = 300;
/**
*/
protected $_screenHight = 200;
/**
*/
protected $_color = 'black';
/**
*/
protected $_control = null;
/**
*/
public function __construct()
{
$this->setControl(new Telecontrol());
}
/**
*/
public function setControl(Telecontrol $control)
{
$this->_control = $control;
return $this;
}
/**
*/
public function getControl()
{
return $this->_control;
}
/**
*/
public function getColor()
{
return $this->_color;
}
/**
*/
public function setColor($color)
{
$this->_color = (string)$color;
return $this;
}
/**
*/
public function getIdentity()
{
return $this->_identity;
}
/**
*/
public function setIdentity($id)
{
$this->_identity = (int)$id;
return $this;
}
public function __clone()
{
$this->setIdentity(0);
}
}
/**
*/
class Telecontrol
{
}
다음은 이런 텔레비전 대상을 복제하고 텔레비전의 리모컨 대상을 관찰한다.
PHP 코드
$tv1 = new Television();
$tv2 = clone $tv1;
$contr1 = $tv1->getControl(); // tv1 contr1
$contr2 = $tv2->getControl(); // tv2 contr2
echo $tv1; //tv1 object id #1
echo '
';
echo $contr1; //contr1 object id #2
echo '
';
echo $tv2; //tv2 object id #3
echo '
';
echo $contr2; //contr2 object id #2
복제된 후에 우리는 대상 id를 살펴보았는데 clone 조작을 통해 tv1에서 tv2를 복제했다. tv1과 tv2의 대상 id는 각각 1과 3이다. 이것은 tv1과 tv2는 두 개의 서로 다른 텔레비전 대상을 인용한 것으로 clone 조작의 결과에 부합된다.그리고 우리는 tv1의 리모컨 대상인 contr1과 tv2의 리모컨 대상인 contr2를 각각 얻었다. 그들의 대상 id를 보면 contr1과 contr2의 대상 id가 모두 2라는 것을 알 수 있다. 이것은 그들이 같은 대상에 대한 인용임을 나타낸다. 즉, 우리는 tv1에서 tv2를 복제했지만 리모컨은 복제되지 않았다. 모든 텔레비전에 리모컨이 설치되어 있어야 한다. 여기에 tv2와 tv1이 함께 사용하는 리모컨이 있다.이것은 분명히 상식에 맞지 않는다.
이를 통해 알 수 있듯이 클론 작업은 이렇게 큰 결함이 있다. 클론 작업으로 대상을 복제할 때 복제된 대상이 다른 대상에 대한 인용이 있을 때 인용된 대상은 복제되지 않는다.그러나 이런 상황은 매우 보편적이다. 현재'합성/집합 복용'은'계승 복용'을 대체하는 데 많이 제창되고 있다.'합성'과'집합'은 한 대상이 다른 대상에 대한 인용을 가지게 하여 인용된 대상을 복용하는 방법이다.우리는 클론을 사용할 때 이런 상황을 고려해야 한다.그렇다면 clone 대상에서 우리는 어떻게 이런 결함을 해결해야 합니까?아마 너는 전에 언급한 을 금방 생각했을 것이다clone 마술 방법, 이것은 확실히 해결 방안이다.
방안1: 로clone 마술 방법 보완
앞에서 소개한 바와 같이clone 마술 방법의 사용법은clone 방법은 복사된 대상 중의 다른 대상의 인용을 새로운 대상에 다시 인용합니다.다음은 수정된 을 살펴보겠습니다.clone() 마술 방법:
PHP 코드
public function __clone()
{
$this->setIdentity(0);
//
$this->setControl(new Telecontrol());
}
04행에서 우리는 복제된 텔레비전 대상을 위해 리모컨을 다시 설치했다. 우리는 이전의 방법에 따라 대상의 id를 살펴보면 두 텔레비전의 리모컨이 서로 다른 대상 id를 가지고 있다는 것을 발견할 수 있다. 그러면 우리의 문제는 해결되었다.
그러나 이런 방식은 아마도 그리 좋은 편은 아닐 것이다. 만약 복사된 대상 중 여러 개의 다른 대상에 대한 인용이 있다면, 우리는 반드시clone 방법에서 하나하나 다시 설정하면 더 나쁜 것은 복제된 대상의 클래스가 제3자가 제공하면 우리는 코드를 수정할 수 없기 때문에 복제 작업은 기본적으로 순조롭게 완성될 수 없다.
우리는 clone을 사용하여 대상을 복제한다. 이런 복제는 '얕은 복제' 라고 한다. 복제된 대상의 모든 변수는 원래의 대상과 같은 값을 포함하고, 모든 다른 대상에 대한 인용은 여전히 원래의 대상을 가리킨다.즉, 얕은 복제는 고려된 대상만 복제하고 인용된 대상은 복제하지 않는다는 것이다.'얕은 복제'에 비해 당연히'깊은 복제'도 있다. 복제된 대상의 모든 변수는 원래의 대상과 같은 값을 포함하고 다른 대상을 인용하는 변수를 제외한다.복제할 대상이 인용한 대상을 깊이 복제한 것이다.깊이 복제는 몇 층까지 깊이 들어가야 하는지를 결정해야 한다. 이것은 확정하기 어려운 문제이고 순환 인용의 문제가 발생할 수 있기 때문에 이런 것들은 반드시 조심스럽게 처리해야 한다.EMC 솔루션 2는 딥 클로닝 솔루션이 될 것입니다.
방안2: 직렬화로 심도 있는 복제
PHP에는 직렬화(serialize)와 반직렬화(unserialize) 함수가 있는데, 우리는 하나의 대상을 하나의 흐름에 쓴 다음에 흐름에서 대상을 읽으면 대상이 복사된다.JAVA 언어에서 이 과정을'냉장'과'해동'이라고 부른다.다음은 이 방법을 테스트해 보겠습니다.
PHP 코드
$tv1 = new Television();
$tv2 = unserialize(serialize($tv1));//
$contr1 = $tv1->getControl(); // tv1 contr1
$contr2 = $tv2->getControl(); // tv2 contr2
echo $tv1; //tv1 object id #1
echo '
';
echo $contr1; //contr1 object id #2
echo '
';
echo $tv2; //tv2 object id #4
echo '
';
echo $contr2; //contr2 object id #5
출력 결과를 보면 tv1과 tv2는 서로 다른 리모컨을 가지고 있다.이것은 방안 1보다 훨씬 편리하다. 서열화는 하나의 귀속 과정이다. 우리는 대상 내부에서 몇 개의 대상을 인용했는지, 그리고 몇 층의 대상을 인용했는지 상관하지 않아도 철저하게 복제할 수 있다.이 프로젝트를 사용할 때 을 터치할 수 없음을 주의하십시오.clone 마술 방법으로 추가 조작을 완성할 수 있습니다. 물론 우리는 깊이 복제한 후에 clone 조작을 한 번 더 해서 를 터치할 수 있습니다.clone 마술 방법은 효율에 약간의 영향을 미칠 뿐입니다.또한 이 스키마는 복사된 객체 및 참조된 모든 객체의 를 트리거합니다.sleep 및wakeup 마술 방법이기 때문에 이런 상황들은 모두 고려되어야 한다.
총결산
서로 다른 대상 복제 방식은 서로 다른 효과가 있기 때문에 우리는 구체적인 응용 수요에 따라 어떤 방식을 사용하고 복제 방식을 어떻게 개선하는지 고려해야 한다.PHP5의 대상지향 특성은 JAVA와 비교적 가깝기 때문에 우리는 JAVA에서 귀중한 경험을 많이 참고할 수 있을 것이라고 믿는다.
더 많은 PHP 관련 내용에 관심이 있는 독자들은 본 사이트의 주제를 보실 수 있습니다.,,,,,,,, 그리고,,,,,,,
본 논문에서 서술한 것이 여러분의 PHP 프로그램 설계에 도움이 되었으면 합니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.