2012-02-02 36 views
9

Tôi đã làm việc với PHP vài năm nay, nhưng cho đến bây giờ chưa bao giờ cần phải xử lý tuần tự một cách rõ ràng, chỉ sử dụng $_SESSION. Bây giờ tôi có một dự án yêu cầu tôi thực hiện thủ công cơ chế tuần tự hóa cho một số dữ liệu nhất định - và tôi nhận thấy rằng vấn đề cũng có thể áp dụng cho $_SESSION.Thuộc tính "Tạm thời" trong lớp PHP?

Tôi có một lớp học có chứa một số thuộc tính. Hầu hết các thuộc tính này là nhỏ (như trong bộ nhớ tiêu thụ): số, chuỗi tương đối ngắn, vv Tuy nhiên, lớp này cũng chứa một số thuộc tính, có thể chứa các mảng HUGE (ví dụ: toàn bộ kết xuất của bảng cơ sở dữ liệu: 100.000 hàng với 100 trường). Khi nó xảy ra, đây là một trong các lớp cần được tuần tự hóa/deserialised - và, may mắn thay, các thuộc tính chứa các mảng lớn không cần phải được tuần tự hóa, vì chúng chủ yếu là các tác phẩm tạm thời và được xây dựng lại khi cần thiết.

Trong những trường hợp như vậy trong Java, tôi chỉ cần khai báo thuộc tính là transient - và nó sẽ bị bỏ qua khỏi serialisaion. Thật không may, PHP không hỗ trợ các vòng loại như vậy.

Một cách để đối phó với nó là có một cái gì đó như thế này:

class A implements Serializable 
{ 
    private $var_small = 1234; 
    private $var_big = array(...); //huge array, of course, not init in this way 

    public function serialize() 
    { 
     $vars = get_object_vars($this); 
     unset($vars['var_big']); 
     return serialize($vars); 
    } 

    public function unserialize($data) 
    { 
     $vars = unserialize($data); 
     foreach ($vars as $var => $value) { 
      $this->$var = $value; 
     } 
    } 
} 

Tuy nhiên điều này là khá cồng kềnh, như tôi sẽ cần phải cập nhật serialize phương pháp mỗi khi tôi thêm một bất động sản thoáng qua. Ngoài ra, một khi thừa kế được đưa vào chơi, điều này trở nên phức tạp hơn - để giải quyết, vì các thuộc tính tạm thời có thể nằm trong cả lớp con và cấp độ gốc. Tôi biết, nó vẫn có thể thực hiện được, tuy nhiên tôi muốn đại biểu càng nhiều càng tốt cho ngôn ngữ thay vì sáng tạo lại bánh xe.

Vì vậy, cách tốt nhất để giải quyết các thuộc tính tạm thời là gì? Hoặc tôi thiếu một cái gì đó và PHP hỗ trợ này ra khỏi hộp?

Trả lời

7

Php cung cấp __sleep magic method cho phép bạn chọn thuộc tính nào sẽ được sắp xếp theo thứ tự.

EDIT Tôi đã thử nghiệm như thế nào __sleep() làm việc khi thừa kế là trong các trò chơi:

<?php 

class A { 
    private $a = 'String a'; 
    private $b = 'String b'; 

    public function __sleep() { 
     echo "Sleep A\n"; 
     return array('a'); 
    } 
} 

class B extends A { 
    private $c = 'String c'; 
    private $d = 'String d'; 

    public function __sleep() { 
     echo "Sleep B\n"; 
     return array('c'); 
    } 
} 

class C extends A { 
    private $e = 'String e'; 
    private $f = 'String f'; 

    public function __sleep() { 
     echo "Sleep C\n"; 
     return array_merge(parent::__sleep(), array('e')); 
    } 
} 

$a = new A(); 
$b = new B(); 
$c = new C(); 

echo serialize($a) ."\n"; // Result: O:1:"A":1:{s:4:"Aa";s:8:"String a";} 
// called "Sleep A" (correct) 

echo serialize($b) ."\n"; // Result: O:1:"B":1:{s:4:"Bc";s:8:"String c";} 
// called just "Sleep B" (incorrect) 

echo serialize($c) ."\n"; // Caused: PHP Notice: serialize(): "a" returned as member variable from __sleep() but does not exist ... 

// When you declare `private $a` as `protected $a` that class C returns: 
// O:1:"C":2:{s:4:"*a";s:8:"String a";s:4:"Ce";s:8:"String e";} 
// which is correct and called are both: "Sleep C" and "Sleep A" 

Vì vậy, có vẻ như bạn có thể serialize dữ liệu cha mẹ chỉ khi nó được khai báo là bảo vệ: -/

EDIT 2 tôi đã thử nó với giao diện Serializable với đoạn mã sau:

<?php 

class A implements Serializable { 
    private $a = ''; 
    private $b = ''; 

    // Just initialize strings outside default values 
    public function __construct(){ 
     $this->a = 'String a'; 
     $this->b = 'String b'; 
    } 

    public function serialize() { 
     return serialize(array('a' => $this->a)); 
    } 

    public function unserialize($data){ 
     $array = unserialize($data); 
     $this->a = $array['a']; 
    } 
} 

class B extends A { 
    private $c = ''; 
    private $d = ''; 

    // Just initialize strings outside default values 
    public function __construct(){ 
     $this->c = 'String c'; 
     $this->d = 'String d'; 
     parent::__construct(); 
    } 

    public function serialize() { 
     return serialize(array('c' => $this->c, '__parent' => parent::serialize())); 
    } 

    public function unserialize($data){ 
     $array = unserialize($data); 
     $this->c = $array['c']; 
     parent::unserialize($array['__parent']); 
    } 
} 

$a = new A(); 
$b = new B(); 

echo serialize($a) ."\n"; 
echo serialize($b) ."\n"; 

$a = unserialize(serialize($a)); // C:1:"A":29:{a:1:{s:1:"a";s:8:"String a";}} 
$b = unserialize(serialize($b)); // C:1:"B":81:{a:2:{s:1:"c";s:8:"String c";s:8:"__parent";s:29:"a:1:{s:1:"a";s:8:"String a";}";}} 


print_r($a); 
print_r($b); 

/** Results: 
A Object 
(
    [a:A:private] => String a 
    [b:A:private] => 
) 
B Object 
(
    [c:B:private] => String c 
    [d:B:private] => 
    [a:A:private] => String a 
    [b:A:private] => 
) 
*/ 

Vì vậy, để tổng hợp: bạn có thể tuần tự hóa các lớp qua __sleep() chỉ khi họ không có thành viên riêng trong lớp học siêu hạng (cần phải được sắp xếp theo thứ tự). Bạn có thể tuần tự hóa đối tượng phức tạp thông qua giao diện Serializable, nhưng nó mang lại cho bạn một số chi phí lập trình.

+1

'__sleep' sẽ không hoạt động với các thuộc tính riêng tư trong lớp cha, vì vậy nó chỉ hữu ích miễn là thừa kế không liên quan. –

+0

@AleksG ha! Tôi đã có giải pháp hoạt động! Hãy xem :) – Vyktor

+0

Cảm ơn, nó trông giống như một cách tiếp cận khả thi. Tôi sẽ thử nghiệm nhiều hơn một chút với điều này để xem nó hoạt động như thế nào. –

0

Bạn có thể sử dụng __sleep and __wakeup. Đối với trước đây, bạn cung cấp một mảng các tên thuộc tính đối tượng mà bạn muốn tuần tự hóa. Bỏ qua các thành viên "tạm thời" từ danh sách này.

__wakeup được gọi ngay lập tức khi một cá thể không được thực hiện. Bạn có thể sử dụng điều này để, ví dụ, nạp tiền các thuộc tính không tạm thời trên một số điều kiện.

Các vấn đề liên quan