Если в качестве разработчика PHP вы снова и снова пишете один и тот же код или имеете дело со все более и более удушающим массивом пользовательских функций и включением файлов в свой сценарий, возможно, пришло время заняться объектно-ориентированным программированием (ООП). ООП действительно вступил в свои права за последние 5 лет или около того. Во всем мире разработчики приложений и веб-приложений открыли для себя преимущества этого типа разработки программного обеспечения, и теперь ваша очередь!
В этой статье я расскажу вам об основных принципах и возможностях объектно-ориентированного программирования, существующих на языке PHP, и расскажу о нескольких простых примерах, чтобы вы могли увидеть, как все это работает. Затем мы возьмем это новое знание и применим его к практической проблеме. Вместе мы создадим повторно используемый компонент, который будет обрабатывать разбиение наборов результатов MySQL на страницы.
Пристегнитесь; Я вижу объекты на дороге впереди — это будет ухабистая поездка!
Что такое большая идея?
Хотя само объектно-ориентированное программирование не всегда простое, его основная идея довольно проста для понимания.
Основная цель объектно-ориентированного программирования — связать данные (в форме переменных) с кодом, который отвечает за работу с ними.
Таким образом, вместо одного большого беспорядка переменных с одним большим беспорядком кода PHP, ООП заставил бы вас разбить вашу проблему на более мелкие (и в идеале более организованные) группы переменных и кода. Эти связки могут затем работать вместе, чтобы произвести желаемый эффект. Если вы действительно хорошо выполняете свою работу, вы можете даже взять некоторые из этих пакетов и перенести их прямо в другой проект в будущем, избавив себя от необходимости перерабатывать эту функциональность в следующий раз, когда она вам понадобится.
Итак, чтобы быть ясным, ООП фактически не позволяет вам делать то, что вы уже не могли делать с большими путями кода и переменных; это действительно более организованный способ работы. И если вы чем-то похожи на меня, ваши PHP-скрипты могут использовать всю помощь, которую они могут получить в организационном отделе!
Допустим, вам надоело писать код подключения к базе данных каждый раз, когда вы разрабатываете новый управляемый базой данных веб-сайт на PHP. Вы можете объединить все переменные (имя пользователя, пароль, имя хоста, имя базы данных и т. Д.) И весь код (подключение к серверу базы данных, выбор базы данных, проверка на наличие ошибок и т. Д.), Связанные с подключением к базе данных, в один пакет, называемый объектом . После этого вы можете использовать этот объект для обработки вашего соединения с базой данных.
Не будь квадратом
Хорошо, давайте посмотрим правде в глаза: прямоугольники не были интересны с геометрии 2-го класса. Но они дают нам простой простой пример для начала, и если вы действительно занялись веб-разработкой, надеясь на ручной труд, вы можете сделать вид, что они кирпичики.
Допустим, какой-то ученик 2-го класса, у которого нет геометрии, заплатил вам за то, что вы написали PHP-скрипт, который выполняет вычисления на прямоугольниках. В условиях спада на рынке у вас нет возможности выбирать, поэтому вы берете работу.
Вы начинаете с простой формы HTML, чтобы позволить студенту ввести ширину и высоту прямоугольника:
<form action="domyhomework.php" method="get"> Width: <input type="text" name="w" /><br /> Height: <input type="text" name="h" /><br /> <input type="submit" /> </form>
Теперь domyhomework.php
— скрипт, который будет обрабатывать эту форму — может просто взять ширину и высоту и вычислить характеристики прямоугольника:
<?php $area = $w * $h; $perimeter = ($w + $h) * 2; ?> <html> <body> <p>Width: <?=$w?><br /> Height: <?=$h?></p> <p>Area: <?=$area?><br /> Perimeter: <?=$perimeter?></p> </body> </head>
Красиво и просто, но если вы заработали репутацию написания скриптов с прямоугольниками (эй, это может произойти!), Вы можете устать писать код для расчета площади и периметра снова и снова.
Если вы узнали о функциях PHP, вы можете решить написать две функции для выполнения этих вычислений во включаемом файле. Допустим, вы пишете файл с именем rect.php
, который содержит только следующий код:
<?php function rect_area($width,$height) { return $width * $height; } function rect_perim($width,$height) { return ($width + $height) * 2; } ?>
Затем вы можете использовать эти функции в любом файле, который нуждается в них. Вот наш пересмотренный domyhomework.php
:
<?php require('rect.php'); // Load rectangle functions $area = rect_area($w,$h); $perimeter = rect_perim($w,$h); ?> <html> <body> <p>Width: <?=$w?><br /> Height: <?=$h?></p> <p>Area: <?=$area?><br /> Perimeter: <?=$perimeter?></p> </body> </head>
Теперь все это хорошо, но с объектно-ориентированным программированием мы можем добиться большего!
Объектно-ориентированная версия
Как я объяснил выше, целью ООП является объединение данных (в данном случае переменных ширины и высоты) вместе с кодом для работы с ними (две наши функции для вычисления площади и периметра).
Давайте rect.php
так, чтобы вместо определения пары функций он определял класс, из которого мы можем создавать (создавать экземпляры) объекты прямоугольника:
<?php class Rectangle { var $width; var $height; function Rectangle($width, $height) { $this->width = $width; $this->height = $height; } function area() { return $this->width * $this->height; } function perimeter() { return ($this->width + $this->height) * 2; } } ?>
Давайте рассмотрим этот код по несколько строк за раз, чтобы я мог объяснить его сверху вниз:
Мы начнем с объявления, что мы пишем класс с именем Rectangle
.
class Rectangle {
Имена классов, по соглашению, всегда должны начинаться с заглавной буквы. Это не требуется PHP, но, следуя установленному стандарту, ваш код будет легче читать и поддерживать другим разработчикам.
Далее мы объявляем две переменные: $width
и $height
.
var $width; var $height;
Однако это не просто обычные переменные PHP! Поскольку они появляются внутри определения класса, мы фактически объявляем переменные, которые будут существовать внутри каждого объекта этого класса. Помните: мы рисуем чертежи, из которых будут построены прямоугольные объекты. Итак, в основном мы говорим PHP, что каждый прямоугольник должен иметь ширину и высоту. На языке ООП переменные, принадлежащие объектам, называются свойствами . Итак, мы только что объявили два свойства объектов Rectangle
.
Далее, функция:
function Rectangle($width, $height) {
Как и с указанными выше переменными, функции, объявленные внутри определения класса, будут принадлежать каждому объекту этого класса. Эта функция особенная, потому что она имеет то же имя, что и класс ( Rectangle
). Такая функция называется конструктором и вызывается при создании экземпляра объекта, как мы вскоре увидим.
Конструкторы отвечают за настройку вновь созданного объекта, чтобы он был готов к использованию. В случае нашего класса Rectangle
нам нужно указать свойства (переменные) ширины и высоты, которые мы объявили выше их начальных значений. Как вы можете видеть выше, эта функция-конструктор принимает два параметра: $width
и $height
. Давайте посмотрим, как конструктор присваивает значения этих параметров соответствующим свойствам объекта:
$this->width = $width; $this->height = $height; }
В любой функции, являющейся частью определения класса, специальная переменная $this
относится к объекту, которому принадлежит функция. Таким образом, в приведенном выше коде оба вхождения $this
означают «этот объект Rectangle
».
Оператор со стрелкой ( ->
) на первый взгляд может показаться страшным, но на самом деле все довольно просто. Он используется для доступа к переменным и функциям, которые принадлежат объекту. Итак, в приведенном выше $this->width
ссылается на переменную $width
мы объявили выше — свойство width
this
объекта. Аналогично, $this->height
ссылается на переменную $height
которая принадлежит this
объекту.
Имея это в виду, наша функция-конструктор берет $width
(первый параметр, переданный функции) и присваивает ей $this->width
(свойство width
этого объекта), а также принимает $height
(второй параметр) и присвоение его $this->height
.
Позже мы увидим, как мы можем использовать этот конструктор для создания нового объекта Rectangle
с заданной шириной и высотой. В настоящее время давайте перейдем к нашим (уже знакомым) функциям расчета площади и периметра:
function area() { return $this->width * $this->height; } function perimeter() { return ($this->width + $this->height) * 2; } }
Они очень похожи на функции rect_area
и rect_perim
мы объявили в предыдущем разделе, но вы заметите, что эти функции не принимают никаких параметров ширины / высоты. Как и переменные ( $width
и $height
), которые мы объявили выше, эти функции будут принадлежать каждому объекту, который создается из этого класса. Если мы создадим три разных объекта Rectangle
, каждый из них будет иметь свою собственную функцию area
и perimeter
. Так же, как переменные, которые принадлежат объектам, называются свойствами , функции, которые принадлежат объектам, называются методами .
Теперь, имея это в виду, должно стать ясно, почему методы area
и perimeter
не требуют параметров. Задача этих функций — не вычислять площадь и периметр любого прямоугольника. Их работа состоит в том, чтобы вычислить эти значения для их прямоугольника!
Поэтому, если вы внимательно посмотрите на функции, вы заметите, что они используют $this->width
и $this->height
качестве значений ширины и высоты. Еще раз, мы используем $this
для обозначения «объекта, к которому я принадлежу».
Чтобы увидеть, как все элементы этого объявления класса собираются вместе для создания рабочего объекта, давайте пересмотрим domyhomework.php
чтобы использовать наш новый объектно-ориентированный подход к прямоугольникам.
Rectangle Calculator 2.0
Прежде чем мы погрузимся в наш новый скрипт вычисления прямоугольника, нам нужно узнать, как создать объект из класса. То есть мы заложили чертежи для прямоугольника, но нам еще предстоит его создать. Вот как:
new Rectangle( width , height )
Ключевое слово new
сообщает PHP, что вы хотите, чтобы оно создавало новый объект, и именно это отвечает за магию. Говоря новый Rectangle
, мы говорим PHP создать экземпляр нашего класса Rectangle
. Теперь запомните, что объявленная нами функция конструктора принимает два параметра — ширину и высоту создаваемого прямоугольника — поэтому мы должны указать эти значения здесь ( width
и height
).
Так, например, чтобы создать прямоугольник 10 на 20 и поместить его в переменную с именем $myRectangle
, мы использовали бы следующую строку кода PHP:
$myRectangle = new Rectangle(10,20);
Мы могли бы изменить ширину прямоугольника:
$myRectangle->width = 50;
А затем распечатайте его площадь:
echo $myRectangle->area(); // Prints out '1000'
Что еще более важно, мы можем создать два прямоугольника и поиграть с ними вместе:
$rect1 = new Rectangle(10,20); $rect2 = new Rectangle(30,40); echo $rect1->area(); // Prints out '200' echo $rect2->perimeter(); // Prints out '140'
Теперь, когда мы знаем, как создавать и использовать объект Rectangle
, мы можем создать пересмотренный скрипт domyhomework.php
:
<?php require('rect.php'); // Load rectangle functions $r = new Rectangle($w,$h); ?> <html> <body> <p>Width: <?=$r->width?><br /> Height: <?=$r->height?></p> <p>Area: <?=$r->area()?><br /> Perimeter: <?=$r->perimeter()?></p> </body> </head>
Видите, насколько элегантен код? Мы создаем прямоугольник, указав его ширину и высоту, и с тех пор объект обрабатывает все детали для нас. Все, что нам нужно сделать, чтобы определить площадь и периметр прямоугольника, — это запросить их, вызвав соответствующие методы. Такое качество ООП, когда функциональность скрыта внутри объектов, поэтому разработчику, который ее использует, не нужно знать, как оно работает, называется инкапсуляцией .
Если вам интересно более подробно прочитать об объектно-ориентированных функциях PHP, я отошлю вас к главе 13 Руководства по PHP . Основы, которые мы видели до этого момента, достаточны для большинства применений объектно-ориентированного кода в PHP.
Но хватит прямоугольников! Давайте теперь разработаем что-нибудь полезное, не так ли?
Постраничный набор результатов
Один из самых отягчающих моментов кода, который нужно писать с нуля каждый раз, когда вам это нужно, — это то, что позволяет вам представлять большой набор результатов базы данных на страницах, по которым пользователь может перемещаться. С нашими новыми навыками ООП мы можем разработать класс многократного использования, который сделает всю работу за нас!
В отличие от приведенного выше примера на основе прямоугольника, лучший способ разработки класса — это решить, как вы хотите, чтобы объекты этого класса вели себя, а затем кодировать его в соответствии с этими спецификациями. В программистском жаргоне мы начинаем с определения интерфейса для нашего класса.
Допустим, у нас есть база данных шуток (читатели моей книги будут знакомы с этим примером), и у нас есть следующая таблица Jokes
, где столбец AID
ссылается на записи в таблице Authors
:
Теперь, скажем, мы хотели написать скрипт PHP, который бы перечислял все шутки данного автора, но отображал бы только 5 за раз и позволял бы пользователю перемещаться по этим страницам из 5 шуток.
При использовании традиционных сценариев такое приложение будет содержать некоторый относительно длинный PHP-код на странице, но вот как это выглядит, если мы используем объект для выполнения всей работы:
<?php require('pagedresults.php'); $cnx = @mysql_connect('localhost','kyank','********'); mysql_select_db('jokes',$cnx); $rs = new MySQLPagedResultSet("select * from jokes where aid=$aid", 5,$cnx); ?> <html> <head> <title>Paged Results Demo</title> </head> <body> <table border="1"> <?php while ( $row = $rs->fetchArray() ): ?> <tr><td><?=$row['JokeText']?></td><td><?=$row['JokeDate']?></td></tr> <?php endwhile; ?> </table> <p><?= $rs->getPageNav("aid=$aid") ?></p> </body> </html>
Разделы, выделенные жирным шрифтом, указывают, где объект (класса MySQLPagedResultSet
) вступает в игру. Все остальное должно выглядеть довольно стандартно, если вы работали с PHP какое-то время. Давайте разберемся с этим:
require('pagedresults.php');
Как и в нашем примере с прямоугольником, мы поместили определение нашего класса в отдельный файл. Это не только делает код менее запутанным, смешанным с нашим HTML, но также позволяет нам повторно использовать класс на других страницах и сайтах, просто добавляя файл на любую страницу, которая ему нужна.
После подключения к серверу MySQL и выбора нашей базы данных мы создаем объект:
$rs = new MySQLPagedResultSet("select * from jokes where aid=$aid", 5,$cnx);
Как видите, функция конструктора для этого класса принимает три параметра:
- сам запрос SQL
- количество записей, которые мы хотим отобразить на странице (в данном случае 5), и
- ссылка на соединение с базой данных (
$cnx
)
Мы могли бы спроектировать объект так, чтобы мы просто передавали ему нормальный набор результатов MySQL, но я решил включить обработку запроса в объект, чтобы создание экземпляра объекта вместо обычного вызова mysql_query
.
Как только вы получили набор результатов из базы данных, обычная процедура состоит в том, чтобы затем использовать цикл while для пошагового просмотра набора результатов и распечатки его содержимого. Наш постраничный объект набора результатов (который мы только что создали как $rs
) позволяет нам делать то же самое, используя его метод fetchArray
как мы обычно использовали mysql_fetch_array
функцию mysql_fetch_array
:
<?php while ($row = $rs->fetchArray()): ?>
Таким образом, каждый вызов $rs->fetchArray()
будет возвращать массив, представляющий одну строку набора результатов (которая помещается в переменную $row
), пока не будет достигнут конец текущей страницы результатов. В конце страницы $rs->fetchArray()
вернет false
, завершив цикл while.
Осталось только обеспечить навигацию между страницами:
<p><?=$rs->getPageNav("aid=$aid")?></p>
Метод getPageNav
отвечает за создание навигационных ссылок, которые для страницы 4 из 8-страничного набора результатов будут выглядеть следующим образом:
Метод создает ссылки на текущий скрипт, которые содержат специальную переменную с именем resultpage
в строке запроса. Конструктор MySQLPagedResultSet
отслеживает эту переменную и использует ее, чтобы определить, какую страницу результирующего набора отображать.
Поскольку в большинстве случаев SQL-запрос будет включать одну или несколько переменных (в этом случае переменную $aid
для выбора шуток автора для отображения), getPageNav
могут быть переданы любые дополнительные элементы строки запроса. В этом случае мы передаем его "aid=$aid"
, что гарантирует передачу переменной $aid
через любую из сгенерированных ссылок.
Теперь, когда мы увидели, как должен работать объект, мы можем углубиться в реализацию этого интерфейса в классе MySQLPagedResultSet
.
Реализация класса
Мое описание интерфейса, представленное объектами класса MySQLPagedResultSet
без сомнения, дало вам много подсказок о том, как будет работать сам класс. В этом последнем разделе мы рассмотрим код для класса, чтобы увидеть, как он работает. Если ваш единственный интерес заключается в использовании класса в вашем проекте, вы можете скачать pagedresults.php
здесь .
class MySQLPagedResultSet { var $results; var $pageSize; var $page; var $row;
Начнем со списка переменных-членов (также известных как свойства):
-
$results
будет использоваться для хранения фактического набора результатов MySQL. -
$pageSize
будет хранить количество записей, отображаемых на странице. -
$page
будет отслеживать, какая страница набора результатов должна отображаться. -
$row
используется методомfetchArray
для отслеживания текущей строки в наборе результатов.
Далее, конструктор:
function MySQLPagedResultSet($query,$pageSize,$cnx) { global $resultpage;
Как мы и решили, конструктор принимает три параметра — запрос SQL, размер страницы (количество записей на страницу) и соединение с базой данных.
Первое, что мы делаем в этой функции — это получаем доступ к глобальной переменной $resultpage
. Это переменная, getPageNav
метод getPageNav
будет вставлять в навигационные ссылки, чтобы указать, какая страница должна отображаться, поэтому нам необходимо получить доступ к ней здесь, чтобы определить, была ли указана страница.
ПРИМЕЧАНИЕ. PHP 4.1: Начиная с PHP 4.1, рекомендуется отключать опцию
register_globals
в php.ini
и вместо этого обращаться к переменным через один из новых глобальных массивов: $_GET
, $_POST
, $_COOKIE
, $_SERVER
, $_ENV
или $_REQUEST
.Если вы используете PHP 4.1 или более
$resultpage = $_GET['resultpage'];
и решили выполнить эту рекомендацию, вы можете заменить эту первую строку на $resultpage = $_GET['resultpage'];
,
Далее конструктор выполняет запрос, который ему дали:
$this->results = @mysql_query($query,$cnx);
Результаты помещаются в $this->results
— переменную-член, которую мы объявили выше. Пока мы на этом, мы инициализируем $this->pageSize
, которому просто будет дано значение параметра $pageSize
который был передан конструктору:
$this->pageSize = $pageSize;
Наконец, нам нужно установить текущую страницу. Сначала мы должны обратиться к переменной $resultpage
чтобы увидеть, была ли установлена определенная страница. Если переменная окажется пустой (или ошибочно установлена в отрицательное число), мы устанавливаем ее равной 1
чтобы первая страница была выбрана по умолчанию:
if ((int)$resultpage <= 0) $resultpage = 1;
(int)
заставляет PHP $resultpage
(то есть преобразовывать) значение в $resultpage
к целому числу, на тот случай, если кто-то изменил строку запроса и допустил скольжение нечислового значения.
Мы также должны быть уверены, что указанная страница не находится за концом набора результатов. Для этого мы используем метод getNumPages
, который мы getNumPages
увидим:
if ($resultpage > $this->getNumPages()) $resultpage = $this->getNumPages();
Наконец, имея действительный номер страницы в руках, мы передаем значение методу setPageNum
, который вскоре увидим:
$this->setPageNum($resultpage); }
Метод getNumPages
определяет количество страниц в текущем наборе результатов. Этот метод используется внутри других методов класса, в частности конструктора, который мы только что видели.
function getNumPages() { if (!$this->results) return FALSE; return ceil(mysql_num_rows($this->results) / (float)$this->pageSize); }
сfunction getNumPages() { if (!$this->results) return FALSE; return ceil(mysql_num_rows($this->results) / (float)$this->pageSize); }
Как видите, нахождение количества страниц является относительно простым расчетом. Мы просто делим количество строк в наборе результатов ( mysql_num_rows($this->result)
) на размер страницы ( $this->pageSize
), а затем $this->pageSize
, используя PHP-функцию ceil
. Чтобы убедиться, что при делении получается дробное значение, которое можно округлить, мы pageSize
свойство pageSize
к числу с плавающей запятой.
Метод setPageNum
может использоваться для задания страницы просматриваемого набора результатов. Случаи, когда этот метод был бы полезен, довольно редки (попробуйте представить случай, когда вы хотите перейти на определенную страницу набора результатов, но вы не можете передать или переопределить переменную $resultpage
), но конструктор также использует его для установки страницы на $resultpage
переменной $resultpage
. Так что практически вы можете думать об этом как о расширении конструктора.
function setPageNum($pageNum) { if ($pageNum > $this->getNumPages() or $pageNum <= 0) return FALSE; $this->page = $pageNum; $this->row = 0; mysql_data_seek($this->results,($pageNum-1) * $this->pageSize); }
Сначала метод проверяет параметр $pageNum
чтобы убедиться, что это число в допустимом диапазоне страниц. Если нет, возвращается false. Затем он сохраняет новый номер страницы в $this->page
, сбрасывает $this->row
в ноль и, наконец, использует PHP-функцию mysql_data_seek
для перемещения в первую строку выбранной страницы в наборе результатов MySQL, рассчитанную по $pageNum
и $this->pageSize
.
Далее getPageNum
, который возвращает номер текущей страницы:
function getPageNum() { return $this->page; }
Вы спрашиваете, почему метод getPageNum
? В конце концов, если $rs
является MySQLResultSet
, вы можете получить номер страницы из $rs->page
, верно? Ну, взгляните на метод setPage
. Как видите, установка нового номера страницы для набора результатов очень важна. Если пользователь класса решит установить страницу, напрямую изменив $rs->page
, ничего такого не произойдет, и объект не будет работать так, как ожидалось.
Современное мышление об объектно-ориентированном дизайне предполагает, что ни одно свойство не должно быть напрямую доступно извне класса. Скорее, должны быть предоставлены методы для «получения» и «установки» значения каждого свойства, к которому пользователям класса может потребоваться доступ. В большинстве объектно-ориентированных языков это можно реализовать, сделав свойства «закрытыми» и, таким образом, полностью недоступными для внешнего мира.
У PHP нет такого средства для обеспечения конфиденциальности данных, но принцип все еще применяется. Вместо того, чтобы просить пользователя класса запомнить, что, хотя он или она может читать номер страницы напрямую, он всегда должен быть установлен с помощью setPageNum
, мы предоставляем соответствующий метод getPageNum
для извлечения значения и вместо этого делаем все возможное, чтобы отговорить доступ к свойствам напрямую.
Практический пример использования getPageNum
— это если вы хотите отобразить «Страница X из Y» вверху списка результатов. Код для этого будет просто:
<p>Page <?=$rs->getPageNum()?> of <?=$rs->getNumPages()?>.</p>
Вау — много разговоров за такой простой метод! К счастью, следующие два требуют небольшого объяснения:
function isLastPage() { return ($this->page >= $this->getNumPages()); } function isFirstPage() { return ($this->page <= 1); }
Эти две функции позволяют пользователю класса определить, является ли текущая страница первой страницей и / или последней страницей набора результатов. Обе функции возвращают либо true, либо false. Код должен быть довольно понятным.
Все, что осталось, — это два настоящих метода «рабочей лошадки» класса. Во-первых, у нас есть fetchArray
, который заменяет mysql_fetch_array
для наших постраничных наборов результатов:
function fetchArray() { if (!$this->results) return FALSE; if ($this->row >= $this->pageSize) return FALSE; $this->row++; return mysql_fetch_array($this->results); }
Метод возвращает false как в том случае, если результирующий набор, сохраненный в $this->results
имеет значение false (что указывает на неудачный запрос), так и в том случае, если текущий номер строки больше или равен размеру страницы (что указывает на то, что конец страница была достигнута). В противном случае текущий номер строки увеличивается и mysql_fetch_array
для возврата следующей строки в наборе результатов.
И, наконец, «Большая кауна», getPageNav
:
function getPageNav($queryvars = '') {
Как видите, параметру $queryvars
присвоено значение по умолчанию ''
(пустая строка), чтобы сделать его необязательным, поэтому вы можете вызывать getPageNav
без параметров, если вам не нужно передавать какие-либо переменные в строках запроса сгенерированные ссылки.
$nav = ''; if (!$this->isFirstPage()) { $nav .= "<a href="?resultpage=". ($this->getPageNum()-1).'&'.$queryvars.'">Prev</a> '; }
Прежде всего, если текущая страница не является первой страницей (которую мы проверяем с isFirstPage
метода isFirstPage
), мы хотим отобразить ссылку «Предыдущая». URL для ссылки является чистой строкой запроса, так как мы просто ссылаемся прямо на ту же страницу. Строка запроса содержит магическую переменную resultpage
, которая сообщает объекту MySQLPagedResultSet
какую страницу отображать. Мы также добавляем любые дополнительные переменные запроса (как указано параметром $queryvars
) в конец строки запроса.
Вывод этой функции встроен в переменную с именем $nav
, которую мы вернем в конце, а не выводим ее прямо в вывод. Это делает метод немного более гибким, позволяя пользователю класса решать, как обрабатывать вывод.
Следующим шагом является создание списка страниц:
if ($this->getNumPages() > 1) for ($i=1; $i<=$this->getNumPages(); $i++) { if ($i==$this->page) $nav .= "$i "; else $nav .= "<a href="?resultpage={$i}&". $queryvars."">{$i}</a> "; }
Оператор if
гарантирует, что мы создадим список только в том случае, если их несколько. Не имеет смысла просто отображать число «1» внизу списка результатов, не так ли?
Затем мы используем довольно типичный цикл for
для просмотра номеров страниц, выводящих связанный номер для каждой страницы, за исключением текущей страницы (где $i=$this->page
), которую мы печатаем без ссылки.
Наконец, мы распечатываем ссылку «Далее», если текущая страница не последняя (согласно isLastPage
):
if (!$this->isLastPage()) { $nav .= "<a href="?resultpage=". ($this->getPageNum()+1).'&'.$queryvars.'">Next</a> '; } return $nav; } }
Написание класса определенно требует больше времени, чем написание простого кода для выполнения одной и той же работы, но если это работа, которую вы ожидаете выполнить более одного раза за свою карьеру в качестве разработчика PHP, хорошо разработанный класс, такой как этот, может быть экономия времени на будущие проекты!
Примечание о производительности
PHP-скрипты, которые отображают большие наборы результатов базы данных за раз, обычно используют предложение LIMIT
запроса SELECT
в MySQL.
Используя LIMIT
, вы можете указать количество результатов, которые вы хотите получить, а также номер первого результата, который вы хотите получить. Например, вы можете сказать, что хотите выбрать до 5 строк, начиная с 26-го. Это будет эквивалентно получению только строк на 6-й странице постраничного результирующего набора, который отображает 5 записей на страницу.
Если полный набор результатов, с которым вы работаете, вероятно, будет очень большим по сравнению с размером вашей страницы (например, если он содержит сотни записей, и вы отображаете их по пять одновременно), PHP получит полный набор результатов из сервер базы данных (как это делается в классе MySQLPagedResultSet
представленном в этой статье) может быть немного бесполезным с точки зрения производительности.
Если вы находитесь в настроении для вызова, вы можете адаптировать класс из этой статьи так, чтобы он прикреплял соответствующее предложение LIMIT
к концу запроса SELECT
перед отправкой запроса, но вам также нужно, чтобы он анализировал запросить и сгенерировать запрос SELECT COUNT(*)
чтобы определить количество записей в полном наборе результатов.
По моему мнению, за исключением крайних случаев, удобство наличия простого многократно используемого компонента для создания постраничных наборов результатов — в дополнение к сохраненным накладным расходам, не требующим выполнения отдельного запроса для подсчета результатов, — перевешивает потерю производительности получение полного набора результатов.
Резюме
В этой статье я не только ознакомил вас с основами объектно-ориентированного программирования и продемонстрировал, как их можно применять в PHP, но и познакомил вас с разработкой чрезвычайно полезного класса для разбиения наборов результатов MySQL на страницы.
Возможно, этому классу не хватает некоторых функций обычных наборов результатов, или вы хотели бы отображать графические ссылки следующий / предыдущий в отличие от текстовых ссылок, которые мы создали здесь? Все, что вам нужно сделать, это добавить больше методов в класс, чтобы он делал то, что вам нужно! И самое приятное то, что вам нужно написать это только один раз, и вы сможете повторно использовать эту функциональность в любом будущем проекте!