Анимация
JavaScript


Главная  Библионтека 

0 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 [ 159 ] 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

Примечание

Возможно, вы спросите: зачем нам вообще такая функция, когда можно воспользоваться оператором new напрямую? Тогда еще раз перечитайте предпоследнюю фразу предыдущего абзаца: "В случае, если таблица уже существует, новый объект не создается". В то же время оператор new всегда создает новый объект, что нам, конечно, не подходит. Ведь мы договорились никогда не иметь в программе двух разных объектов, связанных с одной и той же таблицей.

Легко сказать - "возвращает уже существующий объект", но несколько сложнее - реализовать это. Рассмотрим два различных способа, с помощью которых мы можем достичь цели.

( Замечание

Как следует из законов Мэрфи, "у любой сложной задачи всегда имеется одно простое, красивое и легкое для понимания неправильное решение". В нашем случае это будет возврат из функции объекта класса MysqlTable "обычным" способом, подразумевающим копирование. Но ведь, по имеющейся между нами договоренности, объекты этого класса нельзя копировать!

Возврат ссылки на объект

Первый прием связан с новой возможностью PHP версии 4 - ссылочными переменными. Помните, в части III этой книги мы говорили, что функция может возвращать ссылку на переменную (объект), а не только копию переменной?.. В нашем случае это оказывается довольно удобно. Вот как могла бы выглядеть функция OpenTable() и использование для нее ссылок (листинг 31.4):

Но обо всем по порядку. Чтобы чуть сгустить краски и не вдаваться в абстрактные рассуждения, давайте предположим, что наш класс MysqlTable вообще не допускает копирования его объектов, а при случайном выполнении такого копирования работает совершенно неправильно. Нужно заметить, что это не так уж и далеко от истины, особенно если мы используем MysqlTable не напрямую, а как базовый для какого-то другого типа (например, для класса форума).

Мы знаем, что в таком случае объекты этого класса можно передать без побочных эффектов внутрь функций по ссылке. Сейчас мы остановимся на обратном процессе. Итак, пусть мы написали более-менее универсальный модуль, в котором есть единственная интерфейсная функция OpenTable(), создающая новую таблицу в базе данных и, соответственно, новый объект класса MysqlTable. Специфика этой функции в том, что в случае, если таблица существует, новый объект не создается, а возвращается уже имеющийся. Иными словами, для двух вызовов функции с одинаковыми параметрами должен быть возвращен один и тот же объект, а не две его копии.



г~-..................................................................................................:

1 Листинг 31.4. Использование ссылок

Массив всех уже открытых таблиц. Ключи - имена таблиц, значения -

соответствующие объекты.

$Tables=array();

Функция OpenTable() возвращает сс1лку на объект, соответствующий таблице MySQL с заданным именем. Копии объектов не создаются. function &OpenTable($name,$Fields="") { global $Tables;

if(!Isset($Tables[$name]))

$Tables[$name]=new MysqlTable($name,$Fields); return $Tables[$name];

Вот так мы должны использовать эту функцию. $Tbl1=&OpenTable("MyTable"); создает нов1й объект $Tbl2=&OpenTable("OtherTable"); создает объект

$TblEqualsTo1=&OpenTable("MyTable"); возвращает имеющийся объект! Теперь $Tbl1 и $TblEqualsTo1 ссылаются на один и тот же объект. То есть изменение $Tbl1 тут же отразится на $TblEqualsTo1, и наоборот.

Опытный программист сразу же заметит в подходе предыдущего примера два значительных недостатка. Оба они связаны с несовершенством механизма управления ссылками в PHP.

□ Если пропустить перед вызовом функции оператор & (взятие ссылки), то функция вернет не ссылку на объект, а копию этого объекта. При этом программа не выдаст никакого предупреждения и, скорее всего, будет даже работать верно - до тех пор, пока для копии объекта не будет вызван метод, ради которого мы и хотели избежать копирования. Вообразите себе муки программиста, отлаживающего такую программу, которая отказалась правильно работать по этой причине - ведь & может быть пропущен очень далеко от того места, где возникла ошибка!

□ У неопытного программиста, использующего ваш класс, может возникнуть искушение скопировать $Tbl1 в новую переменную "обгчным" образом - при помощи оператора =. Или же он может по ошибке пропустить &, когда объявляет функцию со ссылочным параметром.

Мы видим, что два указанных недостатка приводят к тому, что программу становится очень трудно отлаживать. А такие программы, как показал многолетний опыт программирования, не только никуда не годятся - они приносят разработчику лишь огорчения, сокращая его век.



Есть ли альтернатива ссылкам? Оказывается, есть. Правда, она сопряжена с большими сложностями при разработке классов, но зато полностью лишена недостатков, описанных выше. Это - фактическое отделение набора методов, отвечающих за взаимодействие с объектом класса (то есть интерфейса класса) от его реализации.

Возврат интерфейса

Поговорим немного о том, что же собой представляют интерфейсы в объектно-ориентированном программировании. Это понятие довольно сложное, и о нем написано множество томов. Я, разумеется, не собираюсь их здесь пересказывать, потому что эта книга - о PHP, а не об идеологии ООП.

Интерфейсы - главная "изюминка" практически всех сложных объектно-ориентированных систем (например, COM+, CORBA) и одно из основных понятий такого языка, как Java. Язык C++ также во всем поддерживает эту идеологию. Что же может дать нам PHP в этом отношении? К сожалению, довольно немного. И все-таки даже этого хватает, чтобы избавиться от недостатков, присущих ссылкам в PHP - во всяком случае, для нашей задачи.

Психологи утверждают, что яркие ассоциации запоминаются особенно хорошо. Что ж, проверим. Помните, когда мы были маленькими детьми, всем нам рассказывали сказки. Почему бы не заняться этим вновь? Как считаете, а?.. Ну и прекрасно (хотя я, право, не могу знать наверняка, что вы ответили). В скобках я буду давать комментарий, ведущий параллельную линию повествования. Итак, закроем глаза и представим себе большого кита (объект большого и сложного класса, например, MysqlTable), лениво плавающего по просторам океана (расположенного в оперативной памяти). Мы не настолько смелы, чтобы приблизиться к этому киту на достаточно близкое расстояние и дотронуться до него (не хотим использовать свойства или методы объекта напрямую). Если уж быть честными, мы даже не видим этого кита (не можем напрямую использовать в программе этот объект) - он слишком далеко (на него нет ссылок), и уж подавно не можем его сдвинуть с места (скопировать объект в другую переменную). Но зато, как мы знаем, его постоянно сопровождают рыбы-прилипалы (объекты-интерфейсы), маленькие и юркие (имеющие код небольшого размера), которые иногда заплывают достаточно далеко, чтобы мы могли с ними взаимодействовать. Этих рыб нам удалось выдрессировать, так что теперь они могут передавать киту любые наши приказы (передавать запросы на обслуживание) - разумеется, из тех, что сами понимают (для которых имеются соответствующие методы). Конечно, к киту могут "приклеиваться" рыбы-прилипалы различных видов и по-разному дрессированные (объект может иметь несколько разных интерфейсов). Важно то, что мы не можем взаимодействовать с китом никак иначе, кроме как посредством этих рыб-прилипал (не можем напрямую использовать объект). При этом мы имеем право совершенно свободно разводить прилипал в неволе (копировать объекты-интерфейсы), ведь киту (главному объекту) нет до этого ровным счетом никакого дела (в PHP объект "не знает сколько у него интерфейсов и как они используются).



0 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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 [ 159 ] 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189