(Bài tiếp) ArrayObject

Các giao diện mẫu định nghĩa sẵn trong thư viện SPL này dùng để xây dựng lên các lớp SPL.

Giao diện Countable

Giao diện này được định nghĩa như sau:

Countable {
    /* Methods */
    abstract public count ( void ) : int
}

Sử dụng giao này dùng để triển khai các lớp có chứa các phân tử, nó cung cấp hàm trả về số lượng các phần tử counnt(). Ví dụ:

class Products implements Countable
{
    private $_totals;

    public function __construct($_totals)
    {
        $this->_totals = $_totals;
    }

    public function count()
    {
        return $this->_totals;
    }
}

$products = new Products(10);
echo $products->count();

Giao diện Traversable

Traversable {
}

Giao diện này không có hàm nào cả, khi triển khai một lớp theo giao diện này đơn gian là cho biết lớp có thể duyệt các phẩn tử trong nó bằng lệnh foreach.

class Products implements Traversable {
    //.... your code
}

$prducts = new Products();
if ($prducts instanceof Traversable)
    echo 'Dùng được lệnh để duyệt phần tử';
else
    echo 'không dùng được lệnh foreach';

Giao diện Iterator

Giao diện Iterator triển khai từ giao diện Traversable

Iterator extends Traversable {
    /* Methods */
    abstract public current ( void ) : mixed
    abstract public key ( void ) : scalar
    abstract public next ( void ) : void
    abstract public rewind ( void ) : void
    abstract public valid ( void ) : bool
}

Giao diện Iterator là mẫu để xây dựng lên danh sách, triển khai giao diện này bạn cần định nghĩa các hàm theo đúng ý nghĩa của nó như sau:

  • current() : trả về phần tử hiện tại.
  • key(): trả về key của phần tử hiện tại (key do bạn tự xây dựng như: index trong mảng, mãy id sản phẩm ...)
  • next(): trả về phần tử tiếp theo.
  • rewind(): quay trở lại phần tử đầu tiên khi duyệt danh sách.
  • valid(): kiểm tra xem vị trí hiện tại (key hiện tại có hợp lệ).

Giao diện này là triển khai cấu trúc dữ liệu danh sách, danh sách liên kết. Ví dụ danh sách liên kết sau có 5 phần tử

iterator

Ví dụ:

<?php
/***
 * Lớp danh sách 3 sản phẩm liên kết với nhau
 */
class Products implements Iterator {

    // Định nghĩa mảng lưu các phần tử
    private $product = [
        'Phone A',
        'Phone B',
        'Phone C'
    ];

    // Vị trí phần tử hiện tại
    private $_currenproduct = 0;

    // Lấy phần tử hiện tại
    public function current()
    {
       echo 'Call:'.__METHOD__, PHP_EOL;
       return $this->product[$this->_currenproduct];
    }

    // Dịch chuyển đến phần tử tiếp theo
    public function next()
    {
        echo 'Call:'.__METHOD__, PHP_EOL;
        $this->_currenproduct++;
    }

    // Key (định danh) của phần tử hiện tại
    public function key()
    {
        echo 'Call:'.__METHOD__, PHP_EOL;
        return $this->_currenproduct;
    }

    // Kiểm tra hợp lệ Vị trí (index) hiện tại
    public function valid()
    {
        echo 'Call:'.__METHOD__, PHP_EOL;
        return isset($this->product[$this->_currenproduct]);
    }

    // Khởi tạo lại vòng lặp (quay trở lại vị trí phần tử đầu tiên)
    public function rewind()
    {
        echo 'Call:'.__METHOD__, PHP_EOL;
        $this->_currenproduct = 0;
    }
}


// Chạy thử
$products = new Products();
foreach ($products as $key => $product) {
    echo "\t\tResult:".$key, '=>', $product, PHP_EOL;
}

Chạy mã trên ra kết quả:

Call:Products::rewind
Call:Products::valid
Call:Products::current
Call:Products::key
        Result:0=>Phone A
Call:Products::next
Call:Products::valid
Call:Products::current
Call:Products::key
        Result:1=>Phone B
Call:Products::next
Call:Products::valid
Call:Products::current
Call:Products::key
        Result:2=>Phone C
Call:Products::next
Call:Products::valid

Giao diện RecursiveIterator

Giao diện này được định nghĩa như sau:

RecursiveIterator extends Iterator {
    /* Methods */
    public getChildren ( void ) : RecursiveIterator
    public hasChildren ( void ) : bool
    /* Các phương thức kế thừa từ Iterator */
    abstract public Iterator::current ( void ) : mixed
    abstract public Iterator::key ( void ) : scalar
    abstract public Iterator::next ( void ) : void
    abstract public Iterator::rewind ( void ) : void
    abstract public Iterator::valid ( void ) : bool
}

Giao diện này kế thừa giao diện Iterator, nên ngoài các hàm từ Iterator phải định nghĩa có thêm hai hàm getChildrenhasChildrend.

  • getChildren(): Trả về phần tử được hiểu là phần tử con.
  • hasChildren() : kiểm tra phần tử có phần tử con không

Giao diện này là triển khai cấu trúc dữ liệu cây - tree

recursiveiterator

Việc sử dụng giao diện này để xây dựng lên các cấu trúc dữ liệu dạng cây (Tree), dễ dàng đệ quy đến các nhánh. Ví dụ:

<?php
/***
 * Class Products - cây nhiều cấp
 */
class Products implements RecursiveIterator {

    /***
     * @var string - tên sản phẩm
     */
    private $nameproduct;
    /***
     * @var array - mảng các sản phẩm
     */
    private $product = [];

    /***
     * @var int index sản phẩm hiện tại
     */
    private $_currenproduct = 0;

    /***
     * @var Products các sản phẩm con
     */
    private $product_child = null;

    /***
     * @return string
     */
    public function getNameproduct()
    {
        return $this->nameproduct;
    }

    /***
     * Products constructor.
     * @param $nameproduct string - tên sản phẩm khởi tạo
     */
    public function __construct($nameproduct)
    {
        $this->nameproduct = $nameproduct;
    }

    public function current()
    {
        return $this->product[$this->_currenproduct];
    }

    public function next()
    {
        $this->_currenproduct++;
    }

    public function key()
    {
        return $this->_currenproduct;
    }

    public function valid()
    {
        return isset($this->product[$this->_currenproduct]);
    }

    public function rewind()
    {
        $this->_currenproduct = 0;
    }

    /***
     * @return bool - kiểm tra có sản phẩm con
     */
    public function hasChildren()
    {
        return ($this->product_child != null);
    }

    /***
     * @return Products|RecursiveIterator|null - trả về sản phẩm con
     */
    public function getChildren()
    {
        return $this->product_child;
    }

    /***
     * @param $product_child - thiết lập sản phẩm con
     */
    public function setProductChild($product_child)
    {
        $this->product_child = $product_child;
    }

    /***
     * @param $pro - thêm sản phẩm vào dannh sách
     */
    public function addProduct($pro) {
        $this->product[] = $pro;
    }
}



function printproduct($products, $level) {
    echo $level.$products->getNameproduct(), PHP_EOL;
    foreach ($products as $product)
    {
        printproduct($product, $level.'----');
        if ($product->hasChildren())
            printproduct($product->getChildren(), $level.'--------');
    }

}


$products = new Products('Tổng kho');
$dienthoai = new Products('Điện thoại');
$dienthoaidanhsach = new Products('Danh sách điện thoại');

$iphone = new Products('Iphone');
$iphone->addProduct(new Products('Iphone1'));
$iphone->addProduct(new Products('Iphone2'));
$iphone->addProduct(new Products('Iphone3'));

$dienthoaidanhsach->addProduct($iphone);
$dienthoaidanhsach->addProduct(new Products('Nokia'));
$dienthoaidanhsach->addProduct(new Products('Samsung'));
$dienthoai->setProductChild($dienthoaidanhsach);

$products->addProduct($dienthoai);
$products->addProduct(new Products('Tủ lạnh'));
$products->addProduct(new Products('Máy giặt'));

$level = "";
printproduct($products,$level);

Chạy code trên ra kết quả sau:

Tổng kho
----Điện thoại
--------Danh sách điện thoại
------------Iphone
----------------Iphone1
----------------Iphone2
----------------Iphone3
------------Nokia
------------Samsung
----Tủ lạnh
----Máy giặt

Giao diện OuterIterator

OuterIterator extends Iterator {
/* Methods */
public getInnerIterator ( void ) : Iterator
/* Inherited methods */
abstract public Iterator::current ( void ) : mixed
abstract public Iterator::key ( void ) : scalar
abstract public Iterator::next ( void ) : void
abstract public Iterator::rewind ( void ) : void
abstract public Iterator::valid ( void ) : bool
}

Giao diện IteratorAggregate

Dùng để xây dựng lớp tập hợp, cho duyệt qua các phần tử. Giao diện đó như sau:

IteratorAggregate extends Traversable {
 abstract public Traversable getIterator ( void )
}

Đơn giản, lớp xây dựng từ giao diện này, thì khi gọi hàm foreach nó sẽ gọi getIterator để lấy đối tượng cho duyệt.

Ví dụ:

<?php
class myData implements IteratorAggregate {
    public $property1 = "Public property one";
    public $property2 = "Public property two";
    public $property3 = "Public property three";

    public function __construct() {
        $this->property4 = "last property";
    }
    //Hàm này được gọi và trả về giá trị cho lệnh foreach khi bắt đầu được gọi
    public function getIterator() {
        return new ArrayIterator($this);
    }
}

$obj = new myData;

foreach($obj as $key => $value) {
    var_dump($key, $value);
    echo "\n";
}
?>

Giao diện ArrayAccess 

ArrayAccess {
/* Methods */
    abstract public boolean offsetExists ( mixed $offset )// gọi khi gọi hàm isset([])
    abstract public mixed offsetGet ( mixed $offset )//Toán tử lấy giá trị []
    abstract public void offsetSet ( mixed $offset , mixed $value ) //Toán tử gán giá trị []
    abstract public void offsetUnset ( mixed $offset ) // Gọi khi gọi hàm unset([])
}

Giao diện này cho bạn xây dựng ra các đối tượng mà truy cập vào nó giống như mảng.

Ví dụ:

<?php
class obj implements ArrayAccess {
    private $container = array();

    public function __construct() {
        $this->container = array(
            "one"   => 1,
            "two"   => 2,
            "three" => 3,
        );
    }

    public function offsetSet($offset, $value) {
        if (is_null($offset)) {
            $this->container[] = $value;
        } else {
            $this->container[$offset] = $value;
        }
    }

    public function offsetExists($offset) {
        return isset($this->container[$offset]);
    }

    public function offsetUnset($offset) {
        unset($this->container[$offset]);
    }

    public function offsetGet($offset) {
        return isset($this->container[$offset]) ? $this->container[$offset] : null;
    }
}

$obj = new obj;

var_dump(isset($obj["two"]));
var_dump($obj["two"]);
unset($obj["two"]);
var_dump(isset($obj["two"]));
$obj["two"] = "A value";
var_dump($obj["two"]);
$obj[] = 'Append 1';
$obj[] = 'Append 2';
$obj[] = 'Append 3';
print_r($obj);
?>

Giao diện Serializable

Serializable {
    /* Methods */
    abstract public string serialize ( void )
    abstract public void unserialize ( string $serialized )
}

Giao diện này giúp bạn xây dựng một lớp có chức năng serialzable dữ liệu. 

Serialize có nghĩa là sắp theo thứ tự dữ liệu thường với mục đích lưu trữ trên đĩa, vào database ... Sắp xếp dữ liệu theo thứ tự nghĩa là đặt ra một qua tắc riêng sắp xếp dữ liệu đối tượng để lưu trên đĩa, sau đó dựa theo quy tắc này để phục hồi thành đối tượng để sử dụng.

Khi một lớp bạn xây dựng từ giao diện Serializable, thì bạn có thể gọi hai hàm PHP thông dụng là serialize unserialize.

<?php
class obj implements Serializable {
    private $data;
    public function __construct() {
        $this->data = "My private data";
    }
    public function serialize() {
        return serialize($this->data);
    }
    public function unserialize($data) {
        $this->data = unserialize($data);
    }
    public function getData() {
        return $this->data;
    }
}

$obj = new obj;
$ser = serialize($obj);

var_dump($ser);

$newobj = unserialize($ser);

var_dump($newobj->getData());
?>

Đăng ký nhận bài viết mới
(Bài tiếp) ArrayObject