Registry პატერნი გამოიყენება გლობალურ მონაცემებთან სამუშაოდ (გლობალური ცვლადები). ამ პატერნის მეშვეობით შესაძლებელია ორგანიზება გავუკეთოთ ნებისმიერ გლობალურ მონაცემს და შედმგომში ადვილად გამოვიყენოთ ეს მონაცემები. ნაცვლად იმისა რომ გლობალური მონაცემები შევინახოთ PHP-ს გლობალურ $GLOBAL მასივში (რომლის გამოყენებაც აპლიკაციის წერისას არცთუ სასიამოვნო პროცესია), ბევრად ეფექტური იქნება თუ ასეთ მონაცემებთან სამუშაოდ გვექნება რაიმე ჩამოყალიბებული და მოქნილი მექანიზმი. სწორედ ასეთ მექანიზმს წარმოადგენს Registry პატერნი.
PHP-ში გლობალურ მონაცემებთან ორი გზით არის შესაძლებელი:
- global – საკვანძო სიტყვის გამოყენებით
- $GLOBALS – PHP-ს უკვე არსებული მასივი რომელზეც წვდომა შესაძლებელია კოდის ნებისმიერ ადგილიდან
მაგალითში ნაჩვენებია ორივე მეთოდის გამოყენება:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | $myVar = "sample text"; /*$myVar ცვლადი ამ შემთხვევაში ფუნქციის ლოკალური ცვლადია და არაფერი საერთო არ გააჩნია ფუნქციის გარეთ აღწერილ იგივე ცვლადთან */ function printMyVar() { echo $myVar; } /*ამ ფუნქციაში $myVar ცვლადზე წვდომა ხორციელდება global-ის გამოყენებით. ფუნქციის შიდა ცვლადი და მის გარეთ აღწერილი ცვლადი ერთი და იგივეა */ function printMyVar() { global $myVar; echo $myVar; } /*ამ შემთხვევაში $myVar ცვლადს მივმართავთ $GLOBALS მასივის მეშვეობით */ function printMyVar() { $myVar = &$GLOBALS['myVar']; echo $myVar; } /*პირდაპირ გამოიყენება $GLOBALS['myVar']*/ function printMyVar() { echo $GLOBALS['myVar']; } |
როგორც მაგალითებიდან ჩანს გლობალურ მონაცემებთან მუშაობა (თუ ასეთ მონაცემებს ვიყენებთ) შეიძლება საკმაოდ არასასიამოვნო პროცესად იქცეს როდესაც მუშაობა გვიწევს დიდი ზომის სისტემებზე.
ამ პრობლემის არიდება თავისუფლად შესაძლებელია Registry პატერნის გამოყენებით. ამ პატერნის მარტივი რეალიზაცია ნაჩვენებია ქვემოთ მოყვანილ კოდში.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | /** *@access public *@package util */ class Registry { /** @ignore */ var $stack; /** *Default private constructor *@access private */ function Registry() { $this->stack = array(); } /** *@access public *@param string a string specifying object's key *@param mixed an item to be stored during the request */ function add($key, &$item) { $reg = &Registry::getInstance(); $reg->stack[$key] = &$item; } /** *@param string a string specifying object's key *@return mixed an object if it exists in the object stack or null */ function &get($key) { $reg = &Registry::getInstance(); return $reg->stack[$key]; } /** *@param string a string specifying object's key *@return boolean true if an object exists in the object stack or false */ function has($key) { $reg = &Registry::getInstance(); return !is_null($reg->get($key)); } /** *@return Registry the Registry instance */ function &getInstance() { static $registry = array(); if (!$registry) { $registry[0] = &new Registry(); } return $registry[0]; } } |
კოდი შედგება ოთხი მეთოდისგან ესენია:
- add – მეთოდი მონაცემების მასივში ამატებს ახალ ობიექტს მითითებული სახელით
- get – მეთოდი დააბრუნებს ობიექტს მითითებული სახელით, თუ მსგავსი ინახება ობიექტების მასივში
- has – მეთოდი ამოწმებს არსებობს თუ არა ობიექტი მითითებული სახელით ობიექტების მასივში
- getInstance – მეთოდი აბრუნებს უკვე არსებულ Registry კლასის ობიექტს (თუ იგი არ არსებობს წინასწარ ქმნის მასე, ასე რომ ამ მეთოდის პირველი გამოყენების თანავე Registry კლასის ობიექტი იქმნება ერთხელ და ინახება $registry სტატიკურ(static) ცვლადში რაც იძლევე იმის გარანტიას რომ ამ მეთოდის ხელმეორე გამოყენების შემთხვევაში $registry ცვლადი ხელმეორედ აღარ შეიქმნება)
Registry კლასის რეალიზაციაში ცხადად ჩანს რომ იგი რეალიზებულია Singleton პატერნის მეშვეობით.
ამ კლასის გამოყენების მაგალითები მოყვანილია ქვემოთ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class Test { var $testData; function Test() { $this->testData = "this is my test data"; } } $test = &new Test(); Registry::add('test', $test); function useTest() { $test = &Registry::get('test'); echo $test->testData; } class DatabaseConnection() { var $connection; function DatabaseConnection($host, $user, $pass) { $this->connection = mysql_connect($host, $user, $pass); } function getConnection() { return $this->connection; } } $dbConn = &new DatabaseConnection(); Registry::add('db', $dbConn); function useDbConnection() { $db = Registry::get('db'); //$db->getConnection(); } |
მაგალითებში ნათლად ჩანს თუ რამდენად მარტივი და ეფექტურია Registry კლასის გამოყენება. გარდა კლასის ობიექტებისა მისი მეშვეობით შეგვიძლია შევინახოთ ნებისმიერი სხვა ტიპის მონაცემი, იქნება ეს მასივი, სტრიქონი თუ სხვა ნებისმიერი რესურსი.
ტეგები: Design Patterns, PHP
კარგია
ეს ყველაფერი უდავოდ ძალიან სასარგებლოა. მაგრამ 2 შეკითხვა მაქვს, თუმცა მათ არსებითი მნიშვნელობა არ გააჩნიათ. კერძოდ:
1. რა დატვირთვა აქვს ამ კონკრეტულ შემთხვევაში 2 განზომილებიან ‘stack’ მასივს, როცა შეიძლებოდა 1 განზომილებიანი ჩვეულებრივი მასივი გამოგვეყენებინა? ეს შეკითხვა იმიტომ დავსვი, რომ კლასი არსებული ფუნქციების გამოყენებით არ გვაძლევს ‘stack’ – მასივის ორივე განზომილებით მანიპულირების საშუალებას ( 0 – ელემენტი სტატიკურადაა განსაზღვრული);
2. რა დატვირთვა აქვს $registry სტატიკური ცვლადის მასივად გამოცხადებას და შემდეგ მასივის ნულოვან პოზიციაზე ობიექტის განთავსებას? ხომ შეგვეძლო პირდაპირ მიგვენიჭებინა $registry – ცვლადისათვის ახალი ობიექტი new ოპერატორის მეშვეობით?
ამ კოდის ასეთი სახით რეალიზაციას კონკრეტული დანიშნულება აქვს, თუ უბრალო ეს კოდი პროექტიდან არის ამონარიდი, სადაც ამგვარად იყო საჭირო მისი რეალიზება ?
გიორგი
რაც შეეხება $registry ცვლადის მასივად აღწერას და მის ნულოვან(0) ელემენტზე კლასის ობიექტის მინიჭებას გამოწვეულია იმით რომ, სტატიკურ(static) ცვლადს ე.წ. reference ვერ მივანიჭე ვერაფრით(უფრო სწორად, getInstance მეთოდის გამოძახების დროს პირვანდელი მისი მნიშვნელობა იკარგებოდა)… იგივე შეეხება $stack ცვლადს… კოდის პირველ ვერსიაში იგი იყო static ცვლადი თუმცა შემდეგ რეალიზაცია გადავაკეთე ხოლო ძველი კოდის ნაწილი დარჩა… სხვა დატვირთვა მას აღარ გააჩნია
რაც შეეხება $registry ცვლადს, რა თქმა უნდა ვერ შეინახავდი reference – ს, რადგან static ცვლადები reference – ს არ ინახავენ, ანუ getInstance – ის შემდეგ გამოძახებაზე მნიშვნელობა არ გააჩნია $registry ცვლადს და თავიდან ხდება ინიციალიზება. ამის ნაცვლად შეიძლებოდა ასე ჩაგვეწერა კოდი (getInstance – ფუნქცია):
function &getInstance() {
static $registry;
if (!isset($registry)) {
$registry = new Registry();
}
return $registry;
}
ამ კოდშიც ახალი ობიექტი ერთხელ იქმნება და &Registry::getInstance() – გვიბრუნებს მასზე reference – ს, რაც იდეაში გვინდოდა მიგვეღო, ანუ ერთადერთი ნიუანსი ამ კოდში ისაა, რომ static $registry – ცვლადზე reference არ უნდა მივცეთ, რადგან, ისევ აღვნიშვნავ, რომ static ცვლადები reference – ს არ ინახავენ.
რაც შეეხება $stack – ცვლადს, კოდის პირველი ვერსია ნანახი არ მაქვს, მაგრამ ამ ვერსიაში შეგვიძლია ინიციალიზაციის დროს დავწეროთ:
$this->stack = array();
და კოდიდან უბრალოდ [0] – ელემენტი ამოვაგდოთ (ანუ 1 განზომილებიან მასივთან ვიმუშაოთ, ნაცვლად 2 განზომილებიანისა), რის შედეგადაც მივიღებთ იგივე შედეგს რაც გვაქვს ამ მომენტისათვის.
$stack გადავაკეთე… მაგრამ რაც შეეხება ასეთ გამოსავალს:
static $registry;
if (!isset($registry)) {
$registry = new Registry();
}
return $registry;
მაინც არ არის ეს გამოსავალი… მაგ შემთხვევაში new ოპერატორი მაინც ობიექტის კოპიას დააბრუნებს…
ანუ შენ გინდა რომ ერთი კოპიაც არ იყოს, გასაგებია, მაგ შემთხვევაში ყველაფერი რიგზეა
ეს ყველაფერი ჩემი პირადი ინტერესი იყო, სხვა პრობლემა არ ყოფილა, ძალიან სასარგებლო სტატიაა.
[...] ასარიდებლად ყოველთვის ვიყენებ Registry პატერნს, რომლის მეშვეობითაც იოლად ვირიდებ [...]