quang cao 1 quang cao 2
tin tức

PHP 5.3, Phần 2: Bao đóng và các hàm lambda

22/02/2012 - Xem: 3601
Phần 1 của loạt bài xem xét các thay đổi cho lập trình hướng đối tượng và xử lý đối tượng trong PHP 5.3. Phần 2 xem xét các hàm lambda và các bao đóng. Trong Phần 3 dưới đây, chúng ta xem xét các không gian tên (namespaces), là một trong các tính năng được đoán trước nhiều nhất và gây tranh cãi nhất trong bản phát hành này của PHP. Khái niệm về không gian tên đảm bảo cách trợ giúp tránh các vấn đề về nhiều hàm, lớp, và các hằng của cùng tên được định nghĩa nhiều lần.

Các khái niệm về bao đóng và hàm lambda chắc chắn không phải là mới; cả hai đều từ giới lập trình hàm (functional programming). Lập trình hàm là một kiểu lập trình mà chuyển trọng tâm từ khai thác câu lệnh sang đánh giá biểu thức. Các biểu thức này được hình thành bằng cách sử dụng các hàm, chúng được kết hợp với nhau để có các kết quả mà chúng ta có thể đang tìm kiếm. Kiểu lập trình này thường được sử dụng nhiều hơn trong một môi trường hàn lâm, nhưng cũng thấy trong các lĩnh vực của trí tuệ nhân tạo và toán học, và có thể thấy trong các ứng dụng thương mại với các ngôn ngữ như Erlang, Haskell, và Scheme.

Các bao đóng lúc đầu được phát triển trong những năm 1960 như là một phần của Scheme, một trong những ngôn ngữ lập trình hàm nổi tiếng nhất. Các hàm lambda và bao đóng thường gặp trong các ngôn ngữ mà các hàm được xử lý như là các giá trị cấp 1, nghĩa là các hàm có thể được tạo ra ngay và được chuyển như tham số sang ngôn ngữ khác.

Kể từ đó, các hàm bao đóng và lambda đã tìm thấy đường đi ra ngoài giới lập trình hàm và thành các ngôn ngữ như javascript, Python, và Ruby. javascript là một trong những ngôn ngữ phổ biến nhất hỗ trợ các hàm bao đóng và lambda. Nó thực sự sử dụng chúng như là một phương tiện để hỗ trợ lập trình hướng đối tượng, trong đó các hàm được lồng vào các hàm khác để hoạt động như là các thành viên riêng. Liệt kê 1 đưa ra một ví dụ về cách javascript sử dụng các bao đóng.


Liệt kê 1. Một đối tượng javascript được xây dựng nên bằng cách sử dụng các bao đóng
var Example = function()
{ 
this.public = function() 
{ 
return "This is a public method"; 
}; 
var private = function() 
{ 
return "This is a private method"; 
};
};
Example.public()  // returns "This is a public method" 
Example.private() // error - doesn't work

Như chúng ta đã xem trong Liệt kê 1, các hàm thành viên của đối tượng Example được định nghĩa như các bao đóng. Do phương thức riêng bó hẹp trong một biến cục bộ (trái với phương thức chung gắn với đối tượng Example bằng cách sử dụng từ khoá này), nó không thể hiện đối với thế giới bên ngoài.

Bây giờ chúng ta đã thấy một vài quan điểm lịch sử về nơi xuất xứ khái niệm này, hãy quan sát các hàm lambda trong PHP. Khái niệm về các hàm lambda là cơ sở cho các bao đóng và cung cấp cách cải tiến hơn nhiều để tạo ra các hàm khi thực hiện, trái với hàm create_function() có sẵn từ trước trong PHP.

Các hàm lambda

Các hàm lambda (hay “hàm ẩn danh” như chúng thường dẫn) chỉ đơn giản là các hàm sử dụng một lần, có thể được định nghĩa vào bất cứ lúc nào, và thường gắn với một biến. Các hàm tự chúng chỉ tồn tại trong phạm vi của biến mà chúng được định nghĩa, vì vậy khi biến đó vượt ra ngoài phạm vi, thì hàm này cũng không còn. Quan niệm về các hàm lambda có từ công trình toán học trước những năm 1930. Được hiểu như là một phép tính lambda, nó được thiết kế để kiểm tra định nghĩa và ứng dụng hàm, cũng như là khái niệm về phép đệ quy. Sản phẩm từ phép tính lambda được sử dụng để phát triển các ngôn ngữ lập trình hàm, như Lisp và Scheme.

Các hàm lambda rất tiện dụng cho một số cá thể, đáng chú ý nhất đối với nhiều hàm PHP mà chấp nhận một hàm gọi lại (callback function). Một hàm như vậy là array_map(), nó cho phép chúng ta đi qua một mảng và áp dụng một hàm gọi cho từng yếu tố của mảng. Trong các bản trước của PHP, vấn đề lớn nhất với các hàm này là ở chỗ không có một cách sáng sủa nào để xác định hàm gọi lại; chúng ta đã bị tắc ở chỗ nhận một trong ba cách tiếp cận vấn đề sẵn có:

  1. Chúng ta có thể định nghĩa hàm gọi lại ở một nơi nào đó trong mã để chúng ta biết nó là sẵn có. Việc này là tồi do nó chuyển một phần thực hiện cuộc gọi ở nơi khác, mà lại khá bất tiện cho việc đọc và bảo trì, đặc biệt là nếu chúng ta không định sử dụng hàm này ở một nơi khác.
  2. Chúng ta có thể định nghĩa hàm gọi trong cùng một khối mã, nhưng phải có tên. Trong khi việc này giúp giữ các thứ với nhau, chúng ta cần phải thêm một khối if quanh định nghĩa để tránh xung đột vùng tên. Liệt kê 2 là một ví dụ về cách tiếp cận này.


    Liệt kê 2. Định nghĩa một cuộc gọi lại đã có tên trong cùng một khối mã
    function quoteWords()
    {
    if (!function_exists ('quoteWordsHelper')) {
    function quoteWordsHelper($string) {
    return preg_replace('/(\w)/','"$1"',$string);
    }
    }
    return array_map('quoteWordsHelper', $text);
    }
    
  3. Chúng ta có thể sử dụng create_function(), là một bộ phận của PHP từ bản V4, để tạo ra hàm khi chạy. Về mặt chức năng, cho phép thực hiện điều chúng ta muốn, nhưng nó có một vài nhược điểm. Nhược điểm chính là nó được biên dịch lúc đang chạy so với thời gian biên dịch, điều mà sẽ không cho phép các bộ nhớ nhanh chứa mã thao tác (opcode cache) ẩn hàm đó. Đây là cú pháp khá tồi, và việc làm nổi bật chuỗi hiện nay trong phần lớn các IDE chỉ đơn giản là không làm việc.

Mặc dù các hàm mà chấp nhận các hàm gọi lại là mạnh mẽ, không có cách tốt nào để thực hiện một hàm gọi one-off (hàm được làm hoặc xảy ra chỉ một lần) mà không dùng đến việc thiếu đàng hoàng. Với PHP V5.3, chúng ta có thể sử dụng các hàm lambda để lập lại ví dụ trên bằng một cách trong sáng hơn.


Liệt kê 3. quoteWords() sử dụng một hàm lambda cho cuộc gọi lại
function quoteWords()
{
return array_map('quoteWordsHelper',
function ($string) {
return preg_replace('/(\w)/','"$1"',$string);
});
}

Chúng ta thấy cú pháp trong sáng cho phép định nghĩa các hàm này, có thể được tối ưu hóa về hiệu năng bằng các bộ nhớ mã thao tác. Chúng ta cũng đã tăng cường tính dễ đọc và tương thích đã được cải thiện với việc làm nổi bật chuỗi. Hãy xây dựng nên cái này để tìm hiểu về cách sử dụng các bao đóng trong PHP.

Các bao đóng

Các hàm lambda tự chúng không thêm nhiều thứ mà chúng ta trước đây không thể làm. Như đã thấy, chúng ta có thể làm toàn bộ việc này bằng cách sử dụng create_function(), mặc dù với cú pháp tồi hơn và hiệu năng thấp hơn lý tưởng. Tuy nhiên chúng vẫn là các hàm chỉ dùng một lần và không bảo trì bất cứ loại trạng thái mà hạn chế ta có thể làm với chúng. Đây là nơi các bao đóng bước vào và lấy các hàm lambda cho mức tiếp theo.

Bao đóng là một hàm mà được đánh giá về chính môi trường của nó, nó có một hoặc nhiều biến buộc (bound variables) mà có thể truy cập khi gọi hàm. Chúng đến từ giới lập trình hàm, nơi có một số khái niệm. Bao đóng giống như các hàm lambda, nhưng linh lợi hơn về khả năng tương tác với các biến từ ngoài môi trường xác định bao đóng.

Chúng ta hãy quan sát cách định nghĩa một bao đóng trong PHP. Liệt kê 4 cho một ví dụ về một bao đóng cho phép nhập một biến từ môi trường bên ngoài và chi đơn giản hiện chúng lên màn hình.


Liệt kê 4. Ví dụ bao đóng đơn giản
$string = "Hello World!";
$closure = function() use ($string) { echo $string; };
$closure();
Output:
Hello World!

Các biến được nhập từ môi trường bên ngoài được quy định trong mệnh đề use của định nghĩa hàm bao đóng. Theo mặc định, chúng được chuyển theo giá trị, nghĩa là nếu chúng ta cập nhật giá trị đã chuyển trong định nghĩa hàm bao đóng, nó sẽ không cập nhật giá trị bên ngoài. Tuy nhiên chúng ta có thể thực hiện điều này bằng cách mào đầu biến này bằng toán tử &, được sử dụng trong các định nghĩa hàm để xác định cách chuyển tham số theo tham chiếu. Liệt kê 5 chỉ ra một ví dụ về việc này.


Liệt kê 5. Bao đóng chuyển các biến theo tham chiếu
$x = 1
$closure = function() use (&$x) { ++$x; }
echo $x . "\n";
$closure();
echo $x . "\n";
$closure();
echo $x . "\n";
Output:
1
2
3

Chúng ta nhìn thấy bao đóng sử dụng biến ngoài $x và gia tăng nó mỗi khi bao đóng được gọi. Chúng ta có thể trộn các biến chuyển theo giá trị với các biến chuyển theo tham chiếu một cách dễ dàng trong mệnh đề use, và chúng sẽ được xử lý mà không gặp phải bất kỳ vấn đề nào. Chúng ta cũng có thể có các hàm mà trực tiếp trả lại các bao đóng, như xem trong Liệt kê 6. Trong trường hợp này, tuổi thọ của bao đóng sẽ thực sự lâu hơn phương thức mà đã xác định chúng.


Liệt kê 6. Bao đóng được trả lại bởi một hàm
function getAppender($baseString)
{
return function($appendString) use ($baseString) { return $baseString . 
$appendString; };
}

Bao đóng và các đối tượng

Bao đóng có thể là công cụ hữu ích không những cho lập trình thủ tục mà còn cho lập trình hướng đối tượng. Việc sử dụng các bao đóng có cùng một mục đích trong tình trạng này như nó sẽ có bên ngoài một lớp: để chứa một hàm riêng bị phụ thuộc trong một phạm vi nhỏ. Chúng cũng thực sự dễ sử dụng trong các đối tượng của chúng ta khi chúng ở bên ngoài một đối tượng.

Khi được xác định trong một đối tượng, có một điều tiện dụng là bao đóng có đủ quyền truy cập đến đối tượng qua biến $this không cần phải nhập nó tường minh. Liệt kê 7 giải thích việc này.


Liệt kê 7. Bao đóng bên trong một đối tượng
class Dog
{
private $_name;
protected $_color;
public function __construct($name, $color)
{
$this->_name = $name;
$this->_color = $color;
}
public function greet($greeting)
{
return function() use ($greeting) {
echo "$greeting, I am a {$this->_color} dog named 
{$this->_name}.";
};
}
}
$dog = new Dog("Rover","red");
$dog->greet("Hello");
Output:
Hello, I am a red dog named Rover.

Ở đây, chúng ta rõ ràng là sử dụng câu chào được đưa cho phương thức greet() trong bao đóng được xác định trong nó. Chúng ta cũng nắm được màu sắc và tên của chú chó, chuyển qua hàm dựng và lưu lại trong đối tượng, trong bao đóng.

Các bao đóng xác định trong một lớp về cơ bản là giống như những thứ đã định nghĩa bên ngoài một đối tượng. Chỗ khác nhau duy nhất là việc nhập tự động đối tượng qua biến $this. Chúng ta có thể vô hiệu hóa hành vi này bằng cách định nghĩa bao đóng là tĩnh.


Liệt kê 8. Bao đóng tĩnh
class House
{
public function paint($color)
{
return static function() use ($color) { echo "Painting the 
house $color...."; };
}
}
$house = new House();
$house->paint('red');
Output:
Painting the house red....

Ví dụ này giống với lớp Dog được xác định trong liệt kê 5. Khác biệt lớn là ở chỗ chúng ta không sử dụng bất kỳ thuộc tính nào của đối tượng trong bao đóng, do nó được định nghĩa là tĩnh.

Cái lợi lớn của việc sử dụng một bao đóng tĩnh so với bao đóng không tĩnh (nonstatic) bên trong một đối tượng là để tiết kiệm bộ nhớ. Bằng cách không phải nhập đối tượng vào bao đóng, chúng ta có thể tiết kiệm khá nhiều bộ nhớ, đặc biệt là nếu chúng ta có nhiều bao đóng mà không cần tính năng này.

Một điều vui nữa cho các đối tượng là việc thêm vào một phương thức ma thuật tên là __invoke(), cho phép đối tượng tự gọi nó là một bao đóng. Nếu phương thức này được định nghĩa, nó sẽ được sử dụng khi đối tượng đó được gọi vào ngữ cảnh đó. Liệt kê 9 minh hoạ việc này.


Liệt kê 9. Sử dụng phương thức __invoke()
class Dog
{
public function __invoke()
{
echo "I am a dog!";
}
}
$dog = new Dog();
$dog();

Việc gọi tham chiếu đối tượng như trong Liệt kê 9 như biến tự động gọi phương thức ma thuật __invoke() làm cho lớp tự hành động như là một bao đóng.

Các bao đóng có thể tích hợp rất tốt với mã hướng đối tượng, cũng như là với mã thủ tục. Chúng ta hãy xem cách các bao đóng tương tác với API Phản chiếu (Reflection API) mạnh mẽ của PHP.

Bao đóng và phản chiếu

PHP có một API phản chiếu rất hữu ích, nó cho ta kỹ thuật đảo ngược các lớp (reverse-engineer), các giao diện, các hàm, và các phương thức. Theo thiết kế, các bao đóng là các hàm ẩn danh, có nghĩa là chúng không xuất hiện trong API phản chiếu.

Tuy nhiên, một phương thức mới getClosure() đã được thêm vào các lớp ReflectionMethod và ReflectionFunction trong PHP để tạo ra bao đóng một cách năng động từ hàm hoặc phương thức đã quy định. Nó hoạt động như một gộp lớn trong ngữ cảnh này, trong đó việc gọi ra phương thức của hàm thông qua bao đóng gây nên việc gọi hàm trong ngữ cảnh mà nó được định nghĩa. Liệt kê 10 cho biết cách công việc này thực hiện.


Liệt kê 10. Sử dụng phương thức getClosure()
class Counter
{
private $x;
public function __construct()
{
$this->x = 0;
}
public function increment()
{
$this->x++;
}
public function currentValue()
{
echo $this->x . "\n";
}
}
$class = new ReflectionClass('Counter');
$method = $class->getMethod('currentValue');
$closure = $method->getClosure()
$closure();
$class->increment();
$closure();
Output:
0
1

Một hiệu quả phụ thú vị của cách tiếp cận này là ở chỗ nó cho phép chúng ta truy cập các thành viên riêng, được bảo vệ của một lớp, thông qua bao đóng mà có thể rất tiện cho các lớp kiểm thử môđun (unit testing). Liệt kê 11 là một ví dụ về việc truy cập một phương thức riêng trong một lớp.


Liệt kê 11. Truy cập một phương thức riêng trong một lớp
class Example 
{ 
....
private static function secret() 
{ 
echo "I'm an method that's hiding!"; 
} 
...
} 
$class = new ReflectionClass('Example');
$method = $class->getMethod('secret');
$closure = $method->getClosure()
$closure();
Output:
I'm an method that's hiding!

Hơn nữa, chúng ta có thể sử dụng API phản chiếu để tự kiểm tra (introspect) một bao đóng, như trình bày trong Liệt kê 12. Chúng ta chỉ cần chuyển tham chiếu biến sang bao đóng vào hàm dựng của lớp ReflectionMethod.


Liệt kê 12. Kiểm tra một bao đóng bằng cách sử dụng sử dụng API phản chiếu
$closure = function ($x, $y = 1) {}; 
$m = new ReflectionMethod($closure); 
Reflection::export ($m);
Output:
Method [  public method __invoke ] {
- Parameters [2] {
Parameter #0 [  $x ]
Parameter #1 [  $y ]
}
}

Một điều đáng lưu ý về tính tương thích ngược (backward-compatibility) là lớp có tên Closure bây giờ được công cụ PHP dành riêng để lưu giữ các bao đóng, như vậy bất kỳ lớp nào dùng tên đó sẽ cần phải đổi tên.

API phản chiếu hỗ trợ nhiều cho các bao đóng, như chúng đã thấy, ở dạng có thể tạo ra chúng từ các hàm và phương thức hiện hành một cách năng động. Chúng cũng có thể tự kiểm tra chính mình vào một bao đóng giống như một hàm bình thường.

Tại sao lại là bao đóng?

Như chúng ta đã thấy trong các ví dụ về các hàm lambda, một trong những cách sử dụng rõ nhất của các bao đóng là trong một vài hàm PHP mà chấp nhận một hàm gọi như tham số. Tuy nhiên, các bao đóng có thể hữu ích trong bất kỳ ngữ cảnh nào mà chúng ta cần phải đóng gói logic bên trong phạm vi của chính nó. Một ví dụ như vậy xảy ra khi tổ chức cải tiến lại (refactoring) mã cũ để giúp đơn giản hóa nó và làm cho nó có thể đọc hơn. Lấy ví dụ sau đây, nó cho thấy việc ghi log (logger) được sử dụng trong khi chạy một vài truy vấn SQL.


Liệt kê 13. Các truy vấn SQL ghi mã (Code logging SQL queries)
$db = mysqli_connect("server","user","pass"); 
Logger::log('debug','database','Connected to database'); 
$db->query('insert into parts (part, description) values ('Hammer','Pounds nails'); 
Logger::log('debug','database','Insert Hammer into to parts table'); 
$db->query('insert into parts (part, description) values 
('Drill','Puts holes in wood');
Logger::log('debug','database','Insert Drill into to parts table'); 
$db->query('insert into parts (part, description) values ('Saw','Cuts wood'); 
Logger::log('debug','database','Insert Saw into to parts table'); 

Một điểm nổi bật trong Liệt kê 13 là chúng ta đang thực hiện bao nhiêu lần lặp. Mỗi cuộc gọi thực hiện đối với Logger::log() có cùng hai đối số đầu tiên. Để giải quyết việc này, chúng ta có thể đẩy phương thức đó sang một bao đóng và thay vào đó thực hiện các cuộc gọi đối lại bao đóng đó. Mã kết quả như dưới đây.


Liệt kê 14. Các truy vấn SQL ghi mã đã được tổ chức cải tiến lại
$logdb = function ($string) { Logger::log('debug','database',$string); };
$db = mysqli_connect("server","user","pass"); 
$logdb('Connected to database'); 
$db->query('insert into parts (part, description) values ('Hammer','Pounds nails'); 
$logdb('Insert Hammer into to parts table'); 
$db->query('insert into parts (part, description) values 
('Drill','Puts holes in wood');
$logdb('Insert Drill into to parts table'); 
$db->query('insert into parts (part, description) values ('Saw','Cuts wood'); 
$logdb('Insert Saw into to parts table'); 

Không những chúng ta đã khiến mã trong sáng hơn về bề ngoài, mà chúng ta còn làm cho nó dễ thay đổi mức độ ghi log của log truy vấn SQL, do chúng ta bây giờ chỉ cần thực hiện thay đổi ở một nơi.

Tóm tắt

Bài viết này đã chứng minh các bao đóng bổ ích như thế nào khi một việc lập trình hàm xây dựng bằng mã PHP V5.3. Chúng ta đã bàn luận về các hàm lambda và các ưu điểm mà các bao đóng đưa ra cho chúng. Các đối tượng và bao đóng hoà hợp với nhau rất tốt, như chúng ta đã thấy bằng cách xử lý đặc biệt các bao đóng trong mã hướng đối tượng. Chúng ta đã thấy được chúng ta có thể sử dụng API phản chiếu tốt như thế nào để tạo ra các bao đóng động, cũng như là tự kiểm tra chính mình các bao đóng hiện hành.

Liên kết

Tin được quan tâm nhất

Quản cáo

Tags: xo so , kqxs , xo so mien bac , ket qua xo so , ket qua xo so mien bac , so xo , xskt , ket qua so xo , xổ số miền bắc , xs , soi cau xoso , ket qua xsmb , soi cau mb , ket qua , so ket qua , kết quả xổ số , du doan xo so , xo so truc tiep , xosomienbac , soi cau mien bac , du doan xsmb , kqxs mb , xo so hom nay , du doan xo so mien bac , xổ số , soi cau lo , soxo , ket qua xo so hom nay , kết quả xổ số , kết quả , xổ số miền bắc , tần số nhịp , soi cầu lotto , lotto gan , đầu đuôi lotto , đo dàn đặc biệt , chu kỳ đặc biệt , vietlott , sx vietlott , mega , mega 6/45 , power 6/55 , jackpot mega 6/45 , jackpot power 6/55 , xổ số điện toán , xo so dien toan , xổ số mega , vietlott power , xổ số power , jackpot power , power , xổ số miền trung , kết quả xổ số miền trung , kqxs miền trung , xs miền trung , xs mt , kqxs mt , xổ số miền nam , kết quả xổ số miền nam , kqxs miền nam , xs miền nam , xs mn , kqxs mn , lịch vạn niên , xem lịch hôm nay , xem ngày , xem giờ tốt , xem ngày tốt , giờ tốt hôm nay , lịch hôm nay , giờ hoàng đạo , xem giờ hoàng đạo , thiết kế website , thiết kế web giá rẻ , thiết kế web , thiết kế logo , thiết kế ấn tượng , mẫu thiết kế , thiết kế , design website , design web , design logo , design template , design , đồ họa , lập trình , máy tính , hack , hacker , bảo mật , mạng máy tính , công nghệ , thủ thuật , facebook , like , tăng like , fanpage , phần mềm , tin học , thông tin , php , website , web , logo , template , mẫu đẹp , soi cầu mb , du doan xsmb , dự đoán xsmb , du doan xo so mien bac , du doan xs mb , du doán xsmb , xoso minh ngoc , xổ số hà nội , xổ số ha noi , xsmb 30 ngày , xsmb 30 ngay , xsmb30ngay , xo so mien bac 30 ngay , xsmb30 ngày , kết quả xổ số miền bắc hôm nay , kết quả xổ số miên bắc hôm nay , xổ số miền bắc hôm nay , xổ số miên bắc hôm nay , xô sô miên băc hôm nay , xô số miền bắc hôm nay , xổ số miền bắc , kết quả xổ số , ket qua xsmb , ket qua xo so mien bac , ket qua xs mb , xo số miền bắc , kết qua xsmb , xô sô miên băc , xổ số miên bắc , xổ số miền băc , xo so , xổ số , xô số , xôso , xổ sô , xstd , kết quả xổ số miền bắc , kết quả xổ số miên bắc , kếtquảxổ sốmiềnbắc , xsmn , xổ số miền nam , sxmn , kqxs , xổ số miền nam hôm nay , xổ số hôm nay , xo so mien nam , kqxsmn , xs mn , xô số miền nam , xs kt , xo số miền nam , kq xs , xô số hôm nay , xo số mien nam , xỗ số miền nam , xo số miền nam hôm nay , xổ so hôm nay , sxmb , xổ số miền trung , xổ số miền trung hôm nay , xs mt , xô sô miên trung hôm nay , xsmb , kqxsmb , xs mb , xổ số miền bac , kq xsmb , xổ số mien bac , xổ so miền bắc , xs minh ngọc , xsmb thu 6 , xsmb thứ 6 , xs mega , xs bd , xs vl , xo so mien bac thu 6 , xosome , sổ kết quả , quay thử xổ số miền nam , dudoan xsmn , du đoán xsmn , xổ số vietlott , soi cầu , xổ số cần thơ , dự đoán kết quả xổ số siêu chính xác hôm nay , du đoán kết quả xổ số siêu chính xác hôm nay , soi cau du doan xsmb chinh xac 100 , xo so me , xs vietlott , xổ số khánh hòa , xổ số gia lai , xổ số đắk lắk , xổ số bạc liêu , xổ số bình định , xổ số đà nẵng , trực tiếp xổ số miền nam , xsmn thứ 4 , xổ số đồng nai , xổ số thủ đô , dự đoán xổ số miền nam , xổ số miền nam thứ ba , xổ số miền nam trực tiếp , trực tiếp xổ số miền bắc , truc tiếp xổ số miền bắc , xổ số miền bắc trực tiếp , trực tiếp kết quả xổ số miền bắc , trục tiếp kết quả xổ số miền bắc , xổ số miền nam minh ngọc , soi cầu miền bắc , dự đoán xổ số miền bắc , xổ số đại phát , soi cau xo so mien bac , soi cau xs mb , xs bl , xs st , quay thử xổ số miền bắc , thống kê kết quả xổ số miền bắc 100 ngày , xổ số tiền giang , thống kê xổ số miền bắc , truc tiep xsmb , truc tiep xo so mien bac , trưc tiêp xsmb , truc tiếp xsmb , tructiep xsmb , xổ số trực tiếp miền bắc , xổ số bến tre , dd xsmb , xổ số long an , xổ số miền bắc 100 ngày , xsmn thứ 2 , xsmn thu2 , xổ số miền bắc hàng tuần , xổ số miền bắc hàng ngày , xổ số vũng tàu , xổ số miền bắc 30 ngày , xổ số miền nam chủ nhật , xổ số miền nam thứ 6 , xổ số trực tiếp , xổ số miền nam thứ 7 , kết quả xổ số mb , xổ số miền nam thứ 2 , xổ số trực tiếp miền nam , xổ số miền nam thứ tư hàng tuần , xổ số minh ngọc miền nam , xổ số đồng tháp , xổ số trực tiếp hôm nay , xổ số thành phố , xổ số miền bắc thứ sáu hàng tuần , xổ số miền , xổ số miền bắc hôm quả , xổ số tây ninh , xổ số hà nội hôm nay , xsmb truc tiep , xsmb trực tiếp , xổ số miền nam thứ hai , xổ số miền bắc thứ ba , xổ số ba miền , xổ số miền bắc ngày hôm nay , xổ số miền bắc thứ ba hàng tuần , xổ số vĩnh long , xổ số vinh long , xs mien bac , xs mien bắc , xổ số đài bắc , xổ số miền bắc hôm qua , xổ số miền bắc hom qua , xổ số phú yên , ket qua xo so , so xo mien bac , kết quả xsmb , ket qua so xo , ket qua so xo mien bac , xsmn kết quả xổ số miền nam , xo so mien bac hom nay , sổ xô miên bắc hôm nay , kết quả xổ số kiến thiết miền bắc , xs mb hom nay , so xo mien bắc , số xo mien bac , kết qua xo so , ket qua xo số , xổ số kiến thiết miền bắc , kqxs miền bắc , xsmb hôm nay , miền bắc , xổ số kiến thiết miền bắc hôm nay , xsmb xsmn kết quả xổ số miền bắc hôm nay , xổ số hôm nay miền bắc , xsktmb , xskt miền bắc , xs dt , xs mb hôm nay , kqxs mien bắc , xsmbhom nay , xsmb xsmn kết quả xổ số miền bac hôm nay , so xo , xs bt , xổ số mb , kqxs miền nam , kqxs mien nam , ket qua xs mien nam , xo số mb , xo sô mb , xosomienbac , kqxs mien bac , xoso mien bac , xổ số kiên giang , kết quả xổ số miền nam , so xo mien nam , xo so hom nay , số miền nam , xs hom nay , xổ số bình dương , xsmn hom nay , xsmn sxmn kết quả xố số miền nam hôm nay , xổ số sóc trăng , xổ số trà vinh , kết quả xổ số miền nam hôm nay , xổ số chiều nay , xổ số cà mau , xstt , xs mien nam , xổ số kiến thiết miền nam , kết quả xổ số hôm nay , xổ số hồ chí minh , xổ số kiến thiết , ket qua xo so mien nam , xổ số miền nam hôm qua , xổ số miền nam ngày hôm nay , sxmn hôm nay , xo so mn , xs3m , xshom nay , kqsxmn , xổ số ba đài , xskt hôm nay , xosomiennam , xổ số kiến thiết hôm nay , xổ số bình phước , xsbth , xs dn , xs vt , xs tg , xs tn , xskt miền nam , xs ag , xs mn hom nay , xoso mien nam , xổ số hcm , xs bth , số xo mien nam , xsmn sxmn kết quả xổ số miền nam hôm nay , xs kt hôm nay , kết quả xo so mien nam , kết quả xố số hôm nay , kết quả xổ số miền trung , xo so mien trung , so xo mien trung , xs mien trung , kết quả xổ số miền trung hôm nay , xs daklak , xs mtrung , xo so miền trung , xskt mien trung , kq xs mt , xs đăk lăk , sốmientrung , số miền bắc , kết quả xổ số miền bắc ngày hôm nay , kết quả xổ số xsmb , kqxs 30 ngày , kqxsmb hôm nay , kết quả xổ số miền bắc hôm qua , kqxs 30 ngay , sốmienbac , kq xsmb hôm nay , kqxsmb 30 ngày , du doan xsmn , xổ số an giang , xổ số quảng ngãi , xsmb 30 , xsmn thứ 5 , xsmn thứ 6 , quay thu xsmb , soi cau mn , xổ số kon tum , xsmn thứ 7 , xsmn thứ 3 , xsmb 90 ngày , quay thu xsmn , du doan mb , xsmb thu 4 , xsmb thứ 7 , xsmb thu 5 , xổ số minh ngọc hôm nay , xổ số miền bắc thứ hai hàng tuần , xsmb thu 2 , xổ số miền bắc thứ bảy hàng tuần , xổ số miền bắc chủ nhật hàng tuần , xsmn chủ nhật , xổ số hậu giang , xổ số miền bắc thứ tư hàng tuần , xsmb thứ 5 , xổ số đà lạt , xsmb thứ 3 , xsmn thu 6 , xsmb thu 3 , xổ số miền bắc thứ năm hàng tuần , xsmb minh ngoc , xsmb thu 7 , xs khanh hoa , xsmn thu 7 , xs gia lai , xsmn cn , xsmb thứ 4 , xsmb cn , ketquanet , kết quả xổ số miền bắc 30 ngày , xổ số bình thuận , xs da nang , xsmb thứ 2 , xổ số miền nam thứ 3 , xổ số miền bắc chủ nhật , xs kon tum , xsgl , xổ số miền nam thứ sáu hàng tuần , xổ số miền nam thứ tư , xổ số miền nam thứ ba hàng tuần , xổ số miền bắc minh ngọc , xổ số miền nam chủ nhật hàng tuần , xổ số miền nam thứ năm hàng tuần , quay thu mn , xổ số miền bắc thứ bảy , xổ số miền nam thứ bảy hàng tuần , xổ số miền nam thứ hai hàng tuần , xổ số miền bắc thứ hai , xổ số quảng bình , xổ số miền bắc thứ tư , xổ số miền bắc thứ sáu , xổ số miền nam thứ bảy , kết quả xổ số 30 ngày , xổ số 3 miền , xổ số chủ nhật hàng tuần , xổ số miền nam thứ năm , xổ số miền bắc thứ năm , dự đoán xổ số miền trung , ket qua xsmb 30 ngay , xổ số ninh thuận , quay thử xsmb , xổ số miền nam thứ sáu , xổ số thứ tư hàng tuần , thong ke xsmb , kết quả xsmb 30 ngày , xổ số thứ hai hàng tuần , xổ số thứ năm hàng tuần , xổ số thứ bảy hàng tuần , xổ số thứ ba hàng tuần , xsmb 200 ngày , thống kê xsmb , xổ số thứ sáu hàng tuần , xs binh dinh , xsbdi , kqxs minh ngoc , xsmb chu nhat , xstd 30 , soi cầu 666 , xổ số 30 ngày , xsmb chủ nhật , thống kê kết quả xổ số miền bắc , xsmb 90 ngay , xs quang ngai , xsmb 30 ngày gần nhất , dự đoán xsmb minh ngọc , dự đoán xsmb win2888 , truc tiep xsmn , xsmt thứ 2 , xsmb t7 , xsmn t4 , xsmb 200 ngay , soi cau wap , xsmb30 , xsmb minh ngọc , xs khánh hòa , xsmb 100 ngay , xo so phu yen , xsmn thu5 , xsmb 100 ngày , xo so binh dinh , xsmnthu4 , du doan xs , kqxs minh ngọc , xo so quang ngai , xsmnthu3 , xs py , xsmn thu4 , xsmn 30 ngay , soi cau xsmb win2888 , xs gl , xsmn thu6 , xsmnthu5 , xsmb thu3 , xs khánh hoà , xs qng , xstd30 , dự đoán mb , xsmbthu3 , xs hg , trực tiếp xsmn , xs dl , xs mb t7 , xs mn thu 7 , xs mn thu 5 , du doan xsmb win2888 , ket qua xo so mien bac 30 ngay , quay thu xs mb , xs mn thu 3 , xs mn thu 2 , xs mn thu 6 , xs mb thu 4 , xs mb cn , xs mn thu 4 , du doan xsmb minh ngoc , xs binh đinh , xo so mien bac thu 5 , xs mb thu 2 , xs mb chu nhat , dự đoán mn , quay thu xs mn , quay thu xo so mien bac , xs mt thu 2 , xs mn cn , xs khanh hòa , xs mn minh ngoc , thong ke xs mb , xs khanh hoà , dự đoán xsmb minh ngoc , dudoan mn , du đoán mb , xs truc tiep , xs trực tiếp , xs truc tiếp , max 3d , max3d , xsglai , xsmn t7 , số kết quả , xs g lai , xs mn t7 , ket qua vietlott , ket quả vietlott , kết quả vietlott , sosomienbac , kq vietlott , xổ số vietlott hôm nay , vietlott hôm nay , xs tv , xsmchung , dự đoán giải đặc biệt ngày mai , xo so online , dò vé số , dự đoán xổ số , xổ số hà nội trực tiếp , dự đoán kết quả xổ số miền bắc , xổ số me , xổ số mẹ , xô sô me , xổ số miền bắc trực tiếp hôm nay , trực tiếp xổ số miền bắc hôm nay , xổ số ba miền hôm nay , quay thử xổ số miền bắc hôm nay , trực tiếp xổ số miền nam hôm nay , kết quả xổ số vietlott , xổ số cần thơ hôm nay , soi cầu dự đoán xổ số miền bắc hôm nay , kết quả xổ số vietlott hôm nay , dự đoán kết quả xổ số , dự đoán kết quả xổ số miền bắc hôm nay , du đoán kết quả xổ số miền bắc hôm nay , soi cầu xổ số , dự đoán xổ số miền bắc hôm nay , xổ số miền nam trực tiếp hôm nay , trực tiếp kết quả xổ số miền nam , kết quả xổ số trực tiếp miền nam , dư đoán xổ số miền bắc hôm nay , du đoán xổ số miền bắc hôm nay , xổ số trực tiếp miền nam hôm nay , trực tiếp kết quả xổ số miền bắc hôm nay , trực tiếp xổ số hôm nay , soi cầu miền bắc hôm nay , dự đoán xổ số miền trung chính xác 100 , trực tiếp miền bắc , xổ số miền bắc hôm nay trực tiếp , truc tiep kết quả xổ số miền bắc hôm nay , tra cứu kết quả xổ số miền bắc , xs dien toan , xsdientoan , dự đoán xổ số miền nam hôm nay