Mỗi lần tôi nhìn thấy
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
5 trong mã PHP, tôi không khỏi có chút sợ hãi. Từ khóa đơn giản này, mặc dù rất rõ ràng, luôn khiến tôi nghi ngờChính xác thì cái gì sẽ được nhân bản?
Đầu tiên, câu hỏi đưa tôi trở lại những kiến thức cơ bản về PHP. truyền biến theo giá trị hoặc theo tham chiếu. Sau đó, với sự phức tạp của đối tượng nhân bản. mức độ sâu của nó và các phương pháp kỳ diệu khác của PHP
Tóm lại là không có gì yên tâm cả, tiếc là mình đang review code cơ bản
Hôm nay, đối với tôi và đối với bạn nữa, chúng ta sẽ cố gắng tìm ra cách tiếp cận một
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
5 mà không sợ hãi vào lần tớibồi dưỡng
Theo tài liệu,
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
5 sẽ tạo một bản sao nôngKhi một đối tượng được nhân bản, PHP sẽ thực hiện một bản sao nông của tất cả các thuộc tính của đối tượng. Bất kỳ thuộc tính nào là tham chiếu đến các biến khác sẽ vẫn là tham chiếu. tài liệu chính thức
Đây là lúc việc kiểm tra kỹ những điều cơ bản của chúng tôi có vẻ quan trọng đối với tôi, đặc biệt là vì từ vựng được PHP sử dụng để nói về việc truyền giá trị hoặc tham chiếu của biến có thể gây nhầm lẫn
Thật vậy, nếu chúng ta tìm tài liệu về tham chiếu trong PHP là gì, chúng ta sẽ bắt gặp trang này. Người giới thiệu. Thật không may, từ "tham khảo" dường như là một lựa chọn tồi đối với tôi, bởi vì từ đó thường có nghĩa khác trong các ngôn ngữ lập trình khác
Một tham chiếu trong PHP không phải là một con trỏ tới một địa chỉ bộ nhớ, chúng ta có thể xem nó như một bí danh cho cùng một đối tượng. Tài liệu PHP giải thích điều này nhiều lần, trên trang được đề cập ở trên, nhưng cũng ở đây. Đối tượng và tài liệu tham khảo
Nếu bạn muốn đi vào chi tiết hơn, tôi khuyên bạn nên đọc chương này. quản lý bộ nhớ từ PHP Internals
Trên thực tế,
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
5 sẽ tạo một bản sao của đối tượng được yêu cầu bằng cách sao chép các tham chiếu như vậy chứ không phải đối tượng được tham chiếu. Do đó, bản sao nôngVậy câu hỏi đặt ra là đây có thực sự là điều bạn muốn khi sử dụng
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
5 không?Có thể là không.
function objectClassId[mixed $object]: string {
return get_class[$object] . ' #' . spl_object_id[$object];
}
class Birthday {
public function __construct[
// These ints are values
public int $year,
public int $month,
public int $day
] {
echo objectClassId[$this] . ' __construct called' . PHP_EOL;
}
public function __toString[]: string {
return sprintf['%d/%02d/%02d', $this->year, $this->month, $this->day];
}
}
class Person {
public function __construct[
// This string is a value
public string $name,
// This Birthday object is a "reference"
public Birthday $birthday
] {
echo objectClassId[$this] . ' __construct called' . PHP_EOL;
}
}
$aliceBirthday = new Birthday[1985, 9, 21];
$alice = new Person['Alice', $aliceBirthday];
echo $alice->name . PHP_EOL;
echo $alice->birthday . PHP_EOL;
echo "Alice Birthday object hash: " . objectClassId[$alice->birthday] . PHP_EOL;
echo PHP_EOL;
$dolly = clone $alice;
echo "Dolly's name is Alice as expected:" . PHP_EOL;
echo $dolly->name . PHP_EOL;
echo "Dolly's birthday representation is 1985/09/21 as expected:" . PHP_EOL;
echo $dolly->birthday . PHP_EOL;
echo "Dolly's birthday object is the same one as Alice, this can lead to errors:" . PHP_EOL;
echo "Dolly Birthday object hash: " . objectClassId[$dolly->birthday] . PHP_EOL;
echo PHP_EOL;
echo "Let's say Dolly can now have a life of their own:" . PHP_EOL;
$dolly->name = 'Dolly';
$dolly->birthday->year = 1996;
$dolly->birthday->month = 7;
$dolly->birthday->day = 5;
echo $dolly->name . PHP_EOL;
echo $dolly->birthday . PHP_EOL;
echo PHP_EOL;
echo "The problem is that we changed the birthday of Alice too:" . PHP_EOL;
echo $alice->name . PHP_EOL;
echo $alice->birthday . PHP_EOL;
echo PHP_EOL;
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
Tôi không biết bạn thế nào, nhưng khi tôi đọc "bản sao", tôi muốn một đối tượng được sao chép mới và mới, và tôi không tưởng tượng rằng sẽ có bất kỳ tác dụng phụ nào có thể xảy ra
Đó là lý do tại sao cá nhân tôi không thích từ khóa này cho lắm, bởi vì tôi không nghĩ nó phản ánh ý nghĩa của nó
Phép thuật của PHP
Như bạn có thể tưởng tượng, có một giải pháp cho vấn đề này. Thật vậy, PHP có các phương pháp kỳ diệu
Ghi chú. cái được sử dụng nhiều nhất trong số
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
4 này không được gọi khi sao chép một đối tượngHãy kiểm tra cái
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
5. Phương pháp ma thuật này được gọi khi bản sao đã sẵn sàng. Nó có thể được coi là một hàm tạo cho bản sao. Đó là cơ hội để người duy trì một lớp làm những gì cần thiết cho các đối tượng được tham chiếu bởi lớp của họ. Thật không may, việc triển khai này bị ẩn, vì vậy với tư cách là người dùng, chúng ta phải tìm hiểu về API của lớp và kiểm tra hành vi của đối tượng trong quá trình sao chépĐây chủ yếu là lý do tại sao tôi không muốn bắt gặp từ khóa này
class Birthday {
public function __construct[
// These ints are values
public int $year,
public int $month,
public int $day
] {
echo objectClassId[$this] . ' __construct called' . PHP_EOL;
}
public function __toString[]: string {
return sprintf['%d/%02d/%02d', $this->year, $this->month, $this->day];
}
}
class Person {
public function __construct[
// This string is a value
public string $name,
// This Birthday object is a "reference"
public Birthday $birthday
] {
echo objectClassId[$this] . ' __construct called' . PHP_EOL;
}
/**
* As the maintainer of this class/API I took care of that
*/
public function __clone[]: void {
// Most of the time, cloning manually the referred object will do
$this->birthday = clone $this->birthday;
}
}
$aliceBirthday = new Birthday[1985, 9, 21];
$alice = new Person['Alice', $aliceBirthday];
echo $alice->name . PHP_EOL;
echo $alice->birthday . PHP_EOL;
echo "Alice Birthday object hash: " . objectClassId[$alice->birthday] . PHP_EOL;
echo PHP_EOL;
// As the user of this class/API I must check what is the behavior of it when cloned
$dolly = clone $alice;
echo "Dolly's name is Alice as expected:" . PHP_EOL;
echo $dolly->name . PHP_EOL;
echo "Dolly's birthday representation is 1985/09/21 as expected:" . PHP_EOL;
echo $dolly->birthday . PHP_EOL;
echo "Dolly's birthday object is not the same one as Alice anymore:" . PHP_EOL;
echo "Dolly Birthday object hash: " . objectClassId[$dolly->birthday] . PHP_EOL;
echo PHP_EOL;
echo "Let's say Dolly can now have a life of their own:" . PHP_EOL;
$dolly->name = 'Dolly';
$dolly->birthday->year = 1996;
$dolly->birthday->month = 7;
$dolly->birthday->day = 5;
echo $dolly->name . PHP_EOL;
echo $dolly->birthday . PHP_EOL;
echo PHP_EOL;
echo "The problem is now fixed, Dolly and Alice have two different Birthday objects:" . PHP_EOL;
echo $alice->name . PHP_EOL;
echo $alice->birthday . PHP_EOL;
echo PHP_EOL;
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is not the same one as Alice anymore:
Dolly Birthday object hash: Birthday #4
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is now fixed, Dolly and Alice have two different Birthday objects:
Alice
1985/09/21
Tôi nghĩ rằng có nhiều vấn đề với điều này
Đầu tiên, theo ý kiến của tôi, thực tế là việc triển khai nhân bản bị ẩn khỏi người dùng. Tôi đoán điều này có thể chấp nhận được và có thể được coi là một chi tiết triển khai, vì vậy người dùng không phải lo lắng về điều đó, nhưng cá nhân tôi muốn biết chuyện gì đang xảy ra
Khi
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
6 được xác định, thì mọi thứ có vẻ ổn. ?Không, cách tiếp cận ngây thơ của việc nhân bản các đối tượng được tham chiếu trong phương pháp
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
6 của chúng tôi bị hạn chế. Thật vậy, nếu một số đối tượng tham chiếu đến cùng một đối tượng, thì việc sao chép cha mẹ sẽ tạo ra nhiều bản sao hơn so với các tham chiếuOk, tôi đã mất bạn, tôi thừa nhận rằng bản thân tôi cũng khá lạc lõng.
Một ví dụ nhỏ hơn ngàn lời nói.
class Skin {
public function __construct[
// This string is a value
public string $color
] {
echo objectClassId[$this] . ' __construct called' . PHP_EOL;
}
public function __toString[]: string {
return 'Skin color: ' . $color;
}
}
class Arm {
public function __construct[
// This Skin object is a "reference"
public Skin $skin
] {
echo objectClassId[$this] . ' __construct called' . PHP_EOL;
}
/**
* As the maintainer of this class/API I took care of that
*/
public function __clone[]: void {
// Most of the time, cloning manually the referred object will do
$this->skin = clone $this->skin;
}
}
class Person {
public function __construct[
// This string is a value
public string $name,
// Theses objects are "references"
public Arm $leftArm,
public Arm $rightArm,
] {
echo objectClassId[$this] . ' __construct called' . PHP_EOL;
}
/**
* As the maintainer of this class/API I took care of that
*/
public function __clone[]: void {
// Most of the time, cloning manually the referred object will do
$this->leftArm = clone $this->leftArm;
$this->rightArm = clone $this->rightArm;
}
}
$aliceSkin = new Skin['Blue'];
$aliceLeftArm = new Arm[$aliceSkin];
$aliceRightArm = new Arm[$aliceSkin];
$alice = new Person['Alice', $aliceLeftArm, $aliceRightArm];
echo $alice->name . PHP_EOL;
echo "Alice left arm skin object hash: " . objectClassId[$alice->leftArm->skin] . PHP_EOL;
echo "Alice right arm skin object hash: " . objectClassId[$alice->rightArm->skin] . PHP_EOL;
echo PHP_EOL;
// As the user of this class/API I must check what is the behavior of it when cloned
$dolly = clone $alice;
echo "Dolly's name is Alice as expected:" . PHP_EOL;
echo $dolly->name . PHP_EOL;
echo "Dolly skin must be two equal objects but different from Alice " .
"but they are not, our __clone logic is too dumb for that purpose:" . PHP_EOL;
echo "Dolly left arm skin object hash: " . objectClassId[$dolly->leftArm->skin] . PHP_EOL;
echo "Dolly right arm skin object hash: " . objectClassId[$dolly->rightArm->skin] . PHP_EOL;
echo PHP_EOL;
____9Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
0Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
1Nhân bản hay không nhân bản?
Rõ ràng, nó không phải là đơn giản,
Là người duy trì lớp, bạn có thể đánh giá xem nó có phải là một lớp khá cơ bản hay không, chỉ chứa các biến được truyền bởi các giá trị và không có tham chiếu, thì sao chép là cách tao nhã nhất để lấy bản sao của đối tượng. Tuy nhiên, tôi sẽ cẩn thận triển khai và nhận xét phương pháp
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
5. Với tư cách là người dùng API, tôi sẽ thêm nhận xét khi sử dụng từ khóa Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
5 để trấn an người thực hiện việc hiệu đính và đặc biệt là bản thân tôi trong tương laiVề điểm này, như một cải tiến cho IDE, tôi đề xuất rằng
5 PHPDoc nên hiển thị trên từ khóa clone có liên quan cho lớp đã cho, đó sẽ là một cách hay để phơi bày hành vi sao chép của lớp và làm cho nó rõ ràngBirthday #1 __construct called Person #2 __construct called Alice 1985/09/21 Alice Birthday object hash: Birthday #1 Dolly's name is Alice as expected: Alice Dolly's birthday representation is 1985/09/21 as expected: 1985/09/21 Dolly's birthday object is the same one as Alice, this can lead to errors: Dolly Birthday object hash: Birthday #1 Let's say Dolly can now have a life of their own: Dolly 1996/07/05 The problem is that we changed the birthday of Alice too: Alice 1996/07/05
Chúng tôi có một ví dụ về loại bản sao này trong mã Symfony trên một đối tượng đơn giản như
Ở đây, bản sao được sử dụng mà không có vấn đề gì vì bản thân đối tượng chỉ chứa các biến Chuỗi và Boolean
Khi cần tạo một bản sao đầy đủ của một đối tượng phức tạp, thì tôi sẽ sử dụng một thư viện đảm nhận việc đó. Ví dụ: có thể sử dụng github. com/myclabs/DeepCopy, thư viện chuyên làm nhiệm vụ này. Nó quan tâm đến các chi tiết và tránh những lo ngại nêu ra trong bài viết này
Cũng có thể và đôi khi đơn giản hơn để xây dựng lại đối tượng từ đầu, chắc chắn là nhiều dòng hơn, nhưng ít nhất nó rất rõ ràng
Trong mọi trường hợp, tôi mời bạn tránh giải pháp đơn giản mà chúng ta có thể tìm thấy ở mọi nơi trên internet
Birthday #1 __construct called
Person #2 __construct called
Alice
1985/09/21
Alice Birthday object hash: Birthday #1
Dolly's name is Alice as expected:
Alice
Dolly's birthday representation is 1985/09/21 as expected:
1985/09/21
Dolly's birthday object is the same one as Alice, this can lead to errors:
Dolly Birthday object hash: Birthday #1
Let's say Dolly can now have a life of their own:
Dolly
1996/07/05
The problem is that we changed the birthday of Alice too:
Alice
1996/07/05
4Với cách triển khai này, hiệu suất không tốt nhưng tính bảo mật cũng có thể là một vấn đề nếu các đối tượng của bạn chứa dữ liệu do người dùng tạo
Phần kết luận
Mặc dù PHP dường như có những thứ cần thiết để sao chép một đối tượng, nhưng chúng ta đã thấy rằng nó không đơn giản như vẻ ngoài của nó. Như mọi khi, có một số giải pháp và điều quan trọng là sử dụng đúng công cụ cho tình huống nhất định
Cách tiếp cận cá nhân của tôi là đặt câu hỏi về việc sử dụng bản sao trong bối cảnh nhất định, tôi không thể thấy nhiều trường hợp thực tế như vậy. Tôi hy vọng bài đăng trên blog này đã làm bạn yên tâm, không cần phải sợ sao chép các đối tượng trong PHP, nhưng bạn nên xem cách triển khai nó. Đó là một bước bắt buộc để hiểu bản sao sẽ được trả lại cho bạn
hạnh phúc nhân bản
Auteurs & aurices
- Jérôme Gangneux
Développeur Web & Symfony
Twitter GitHub
Bình luận et thảo luận
01/05/2022 11 phút. À chaque fois que je vois clone dans du code PHP, je ne peux m’empêcher d’avoir un peu peur. Ce simple mot clef, en soit pourtant très clair, me met toujours face au doute. Qu’est-ce qui va être cloné précisément ? Lire la suite de l’article La guerre des clones PHPLa guerre des clones PHP
Không bài báo nào sur le même sujet
Khách hàng của Ces ont Profité de notre chuyên môn
JoliCode a formé l’équipe de développement d’Evaneos aux bonnes pratiques pour l’écriture de tests unitaires efficaces et utiles. Nous en avons également profité pour mettre en place une plateforme d’intégration continue pour accompagner l’évolution de la plateforme Voir le projet
Afin de poursuivre son déploiement sur le Web, Arte souhaité être accompagné dans le developpement de son API REST “OPA” [API đích đến là trình hiển thị các chương trình và danh mục video chuỗi]. Trong sự hợp tác của kỹ thuật avec l’équipe Arte, JoliCode a mené un travail spécifique à l’amélioration des Performance et de la fiabilité de l’API. Ces… Voir le projet
À l'occasion de la 12e édition du concours Europan Europe, JoliCode a conçu la plateforme technique du concours. Ce site permet la trình bày các trang web khác nhau pour lesquels il y a un appel à projets, et encadre le processus de recueil des projets soumis par des milliers d'architectes các ứng cử viên. L’application gère également toute la partie post-concours…Làm cách nào để tạo bản sao sâu trong PHP?
Bản sao nông và bản sao sâu trong PHP là gì?
Trình tạo bản sao trong PHP là gì?
Làm cách nào để xác định đối tượng trong PHP?