Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
php_лекции.doc
Скачиваний:
2
Добавлен:
21.09.2019
Размер:
817.66 Кб
Скачать

1. Цикл foreach

Цикл foreac используется для обхода ассоциативных массивов.

//Обход массива в цикле foreach

<?php

$number = array ("first" => "1", "second" => "2", "third" => "3");

foreach($number as $index => $val)

echo "$index = $val <br>";

?>

Результат:

first = 1

second = 2

third = 3

Переменная $кеу для ключа массива необязательна и может быть опущена

2. Цикл for

// Обход массива в цикле for

<?php

$number = array('1","2","3");

for($i=0; $i < count($number); $i++)

echo $number[$i];

?>

Результат: 123.

Функция count() предназначена для вывода количества элементов массива и имеет простой синтаксис:

int count(mixed array)

Обход многомерных массивов

Обход многомерных массивов проводится с помощью вложенных циклов foreach, при этом число вложенных циклов соответствует размерности массива.

// Обход многомерных массивов в цикле

<?php

foreach($ship as $key => $type)

{

echo("<b>$key</b>\n"."\n"); // вывод значений основных массивов

foreach($type as $ship) // вывод значений для каждого из массивов

{

echo("\t<li>$ship</li>\n");

}

}

?>

Основные операции с массивами

  1. Поиск элемента в массиве

Поиск элемента в массиве осуществляется с помощью функции in_array ():

bool in_array(mixed element, array arr [, bool strict])

Эта функция ищет в массиве arr значение element и возвращает true, если оно найдено, и false — в противном случае

<?php

$number = array(0.57, '21.5', 40.52);

if (in_array(21.5, $number)) echo "Значение 21.5 найдено";

else echo "Ничего не найдено";

?>

Для того чтобы функция различала типы элементов в массиве, необходимо третий необязательный параметр strict установить в значение true

Для поиска заданного ключа в массиве можно воспользоваться функцией array_key_exists():

bool array_key_exists(mixed key, array arr)

Функция возвращает true, если ключ key найден в массиве arr .

<?php

$array = array("first_numb" => 1, "second_numb" => 2);

if (array_key_exists("first_numb", $array) echo "OK";

?>

Суперглобальные массивы

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

Для получения доступа к данным, переданным методами get и post, следует обращаться к суперглобальным массивам $_GET и $_POST, соответственно .

<?php

$name = $_GET['name'];

$test = $_POST['test'];

?>

Типы суперглобальных массивов, доступные в РНР.

$_GLOBALS - Содержит ссылку на каждую переменную, доступную в данный момент в глобальной области видимости скрипта. Ключами этого массива являются имена глобальных переменных.

$_SERVER - Переменные, установленные Web-сервером либо напрямую связанные с окружением выполнения текущего скрипта.

$_GET - Переменные, передаваемые скрипту методом get.

$_POST -Переменные, передаваемые скрипту методом post.

$_SESSION - Переменные, передаваемые скрипту через механизм сессий.

$_СООКIЕ - Переменные, передаваемые скрипту через механизм cookies .

$_FILES -Параметры файла, передаваемого скрипту методом post.

$_ENV -Переменные окружения.

$_REQUEST -Переменные, передаваемые скрипту через методы get, post и cookie.

Задания

1. Создайте многомерный массив, характеризующий студентов факультета университета, который будет включать в себя: названия специальностей, имена студентов, курс, год рождения, средний балл. Однородная информация не должна дублироваться в разных элементах массива.

2. Выведите в браузер список студентов каждой специальности, отсортированный по алфавиту в обратном порядке.

Работа со строками

Строки являются основными переменными в РНР, они выступают основными посредниками при операциях с файлами и базами данных, с браузерами и серверами.

Форматирование

Функции printf() и sprintf() позволяют осуществить предварительное форматирование строки и чисел перед непосредственным выводом в окно браузера.

В качестве первого аргумента функция printf() принимает строку форматирования, а в качестве последующих аргументов— переменные, определяемые строкой форматирования (число не ограничено). Строка форматирования, помимо обычных символов, может содержать специальные последовательности символов, начинающиеся со знака %, которые называют определителями преобразования.

<?php

printf("Первое число - %d", 26); // Первое число - 26

?>

Сравнение строк

Осуществлять сравнение строк можно при помощи оператора =, как и любые другие переменные РНР. При сравнении учитывается регистр строк. Для того чтобы сравнение строк выполнялось без учета регистра, необходимо привести строки к верхнему регистру при помощи функции strtoupper() или к нижнему с использованием функции strtolower().

В РНР также имеется специальная функция, осуществляющая сравнение строк— strcmp(). Она принимает два строковых аргумента и возвращает положительное число, если первая строка больше второй, ноль, если строки равны, и отрицательное, если первая строка больше второй.

Аналогичная функция strcasecmp () осуществляет сравнение строк без учета регистра.

Поиск в тексте

Одной из основных строковых функций этого класса является функция substr(), имеющая следующий синтаксис:

string substr(string str, int start [, int length])

Функция substr() возвращает часть строки. Первый аргумент функции str— исходная строка, из которой вырезается текст; второй start— положение в строке, которую нужно вернуть, первого символа (отсчет начинается с нуля); третий length— длина возвращаемой строки в символах. Если третий аргумент не указан, то возвращается вся оставшаяся часть строки.

<?php

$str = "04.05.2005";

echo "день - ".substr($str,0,2)."<br>"; // день - 04

echo "месяц - ".substr($str,3,2)."<br>"; // месяц - 05

echo "год - ".substr($str,6)."<br>"; // год - 2005

?>

Еще одной функцией поиска является strpos(), которая имеет следующий синтаксис:

string strpos(string str, string needle[, int offset])

Эта функция возвращает позицию в строке str, с которой начинается переданная ей подстрока needle.

В РНР имеется функция strrpos (), которая аналогична функции strpos (), за исключением того, что ищется не первое вхождение подстроки, а последнее.

Замена в тексте

Функция замены str_replace() позволяет заменить подстроку в тексте на другую подстроку и имеет следующий синтаксис:

string str_replace(string from, string to, string str)

Функция заменяет в строке str все вхождения подстроки from на to и возвращает результат.

Для удаления начальных и конечных пробелов предназначены функции семейства trim():

ltrim() — удаляет из строки начальные пробелы;

rtrim() —удаляет из строки конечные пробелы;

trim() —удаляет из строки и начальные, и конечные пробелы.

Функция substr_replace() заменяет в исходной строке одни подстроки на другие и имеет следующий синтаксис:

string substr_replace (string str, string replacement, int start[, int length])

Она возвращает строку, в которой часть исходной строки str от символа с позицией start и длиной length заменяется строкой replacement. Если аргумент длины length не указан, замена проводится до конца строки. Если значение аргумента start положительно, то отсчет выполняется от начала строки str, в противном случае— от конца строки. В случае неотрицательного значения length данный аргумент указывает длину заменяемого фрагмента. Если же length отрицательно, то обозначает количество символов от конца строки str до последнего символа заменяемого фрагмента.

Разбивка строк на подстроки

РНР обладает большим набором функций для разбивки строки на подстроки по определенному символу. Первая функция explode() предназначена для разбивки строки по определенному разделителю и имеет следующий синтаксис:

array explode(string separator, string Str[, int limit])

Функция возвращает массив строк, каждая из которых соответствует фрагменту исходной строки str, находящемуся между разделителями, определяемыми аргументом separator. Необязательный параметр limit задает максимальное количество элементов в массиве. Оставшаяся (неразделенная) часть будет содержаться в последнем элементе.

<?php

$str = "Имя, Фамилия, e-mail";

$exp_str = explode(",", $str);

print_r ($exp_str);

?>

Результат:

Array

(

[0] => Имя

[1] => Фамилия

[2] => e-mail

)

Функция implode() является обратной к explode () функцией и осуществляет объединение элементов массива в строку.

Другой функцией, позволяющей разбить строку на подстроки, является strtok(), которая имеет следующий синтаксис:

string strtok(string str, string separate)

Функция strtok() возвращает строку по частям, а именно возвращает часть строки str до разделителя separate. При последующих вызовах функции возвращается следующая часть до следующего разделителя, и так до конца строки. При первом вызове функция принимает два аргумента: исходную строку str и разделитель separate.

// Извлечение подстрок из строки запроса

<?php

$str="http://www.softtime.ru/forum/

read.php?id_forum=1&id_theme=961&id_post=6806";

$tok = strtok($str,"?&");

while($tok = strtok("?&"))

(

echo "$tok<br>";

)

?>

Результат:

id_forum=1

id_theme=961

id__post=6806

Функция str_word_count(), позволяющая как разбивать строку на отдельные слова, так и возвращать число слов в строке.

mixed str_word_count(string str[, int format])

Функция принимает строку str и необязательный параметр format, определяющий, какую информацию следует возвратить о строке. В случае его отсутствия возвращается количество слов в строке. Ниже описаны допустимые значения аргумента format и соответствующие им возвращаемые значения:

1 — возвращается массив, содержащий все слова, входящие в строку str;

2 — возвращается массив, индексами которого являются позиции в строке, а значениями — соответствующие слова.

Функция str_spiit () преобразует строку в массив и имеет следующий синтаксис:

array str_split (string str[, int split_Iength])

Строка str преобразуется в массив. Если указан необязательный аргумент spiit_length, возвращаемый массив будет содержать части исходной строки длиной split_length каждая, иначе каждый элемент будет содержать один символ.

Если split_length меньше 1, возвращается false. Если spiit_iength больше длины строки str, вся строка будет возвращена в первом и единственном элементе массива.

Функция wordwrap() осуществляет перенос на заданное количество символов с использованием символа разрыва строки.

string wordwrap(string str [, int width [, string break [, boolean cut]]])

Функция разбивает блок текста str на несколько строк, которые завершаются символами break (по умолчанию это перенос строки — \n), так, чтобы в одной строке было не более width букв (по умолчанию 75). Поскольку разбиение происходит по границам слов, текст остается вполне читаемым

// Разбиение текста функцией wordwrap ()

<?php

$str = "Здесь может быть любой текст";

$mod_str = wordwrap($str,10,"<br>");

echo($mod_str);

?>

Результат:

Здесь

может быть

любой

текст

Преобразование кодировок

Для преобразования строк из одной кодировки в другую предназначена функция convert_cyr_string ():

string convert_cyr_string(string str, string from, string to)

Функция convert_cyr_string преобразует строку str из кодировки from в кодировку to. Значения аргументов from и to— одиночные символы, определяющие кодировку:

k —KOI8-R;

w —Windows-1251;

i — IS08859-5;

Для преобразования кодировок многобайтовых строк предназначена функция mb_convert_encoding().

string mb_convert_encoding(string str, string to-encoding [, mixed from-encoding])

Функция возвращает строку str, преобразованную из кодировки from- encoding в кодировку to-encoding.

Работа с URL

Функция parse_url() позволяет разбить адрес на отдельные компоненты:

array parse_url(string url)

Функция parse_url() обрабатывает URL , переданный строкой url, и возвращает его компоненты. Массив, возвращаемый функцией, включает множество различных существующих компонентов URL: "scheme", "host", "port", "user", "pass", "path", "query" и "fragment".

// Обработка URL

<?php

$url = "http://www.softtime.ru/forum/read.php?id_forum=l&id_theme=80";

$arr = parse_url($url);

print_r(Sarr);

?>

Результат:

Array

(

[scheme] => http

[host] => www.softtime.ru

[path] => /forum/read.php

[query] => id_forum=l&id_theme=80

)

Для разбора строки с параметрами ("query") имеется специальная функция parse_str():

void parse_str(string str [, array arr])

Функция parse_str() интерпретирует строку str так, как если бы эта строка содержала в себе переменные и их значения и передавалась бы в URL. Если задан второй необязательный параметр аrr, то значения, найденные при помощи этой функции, сохраняются не в глобальных переменных, а в элементах указанного массива.

Согласно спецификации RFC 1738 в URL не допускается использование пробелов, а также символов национальных алфавитов, поэтому для передачи русских слов через строку запроса URL или значение параметра следует преобразовать в безопасный режим при помощи функции urlencode():

string urlencode(string str)

Функция urlencode о возвращает строку , в которой все не алфавитно-цифровые символы, за исключением дефиса, знака подчеркивания и точки заменены знаком процента (%), за которым следуют две шестнадцатеричные цифры, обозначающие код символа.

Работа с датой и временем

Для получения текущего времени и даты предназначена функция time(), которая возвращает количество секунд, прошедших с 0:00:00 1 января 1970 г.

В РНР имеется функция microtime(), возвращающая текущее время в микросекундах.

Для формирования произвольной временной метки следует воспользоваться функцией mktime ():

int mktime([int hour [,int minute [,int second [,int month [,int day [,int year [,int is_dst]]]]]]])

Все принимаемые ею аргументы являются необязательными. Если не передан ни один из аргументов, функция вернет текущее время.

Параметр year может быть двух- или четырехзначным числом. Значения от 0 до 69 соответствуют 2000—2069, а значения от 70 до 99 соответствуют 1970—1999 .

Более применима на практике функция getdate ()

array getdate([int timestamp])

Через необязательный параметр timestamp функции можно передать время (в секундах с 1 января 1970 г.). В случае отсутствия данного параметра функция работает с текущим временем. В качестве результата работы getdate()возвращает ассоциативный массив, содержащий ключи, "seconds" , "minutes" , "hours" , "mday" , "wday" , "mon" , "year" , "yday".

Задания

1. Извлеките из полученной строки имена всех файлов и каталогов и разместите их в массивах $files и $dirs соответственно. Выведите содержимое этих массивов, предварительно отсортировав их.

2. Создайте массив из 10 элементов, значения которых равны факториалу индекса массива (0=>0!, 1=>1!, 2=>2!,..., 9=>9!). Преобразуйте каждый элемент массива в строку из 20 символов таким образом, чтобы цифры были выровнены по левому краю, и выведите содержимое массива в окно браузера.

3. Создайте функцию, которая, принимая строку с HTML-страницей, возвращала бы ее название, заключенное между тегами <title> и </title>.

4. Разбейте строку со временем в формате СУБД MySQL "2010-11-26 11:56:08" на подстроки, содержащие год, месяц, число, часы, минуты и секунды с выводом их в окно браузера.

5. Создайте скрипт, вычисляющий количество минут, прошедших с полуночи 1 января 2000 г. до текущего момента.

Открытие файлов

Файл представляет собой последовательность байтов, хранящуюся на каком-либо физическом носителе информации. Каждый файл имеет абсолютный путь, по которому определяется его местонахождение. В качестве разделителя пути в Windows может использоваться как прямой (/), так и обратный (\) слеш. В других операционных системах используется только прямой слеш.

Открытие файлов в файловой системе сервера производится при помощи функции fopen:

int fopen(string filename, string mode [, int use_include_path])

Первый аргумент filename - имя файла или абсолютный путь к нему. Если абсолютный путь не указывается, то файл должен находится в текущем каталоге.Второй аргумент mode говорит о том, для каких действий открывается файл и может принимать следующие значения:

r (Открыть файл только для чтения; после открытия указатель файла устанавливается в начало файла);

r+ (Открыть файл для чтения и записи; после открытия указатель файла устанавливается в начало файла);

w (Создать новый пустой файл только для записи; если файл с таким именем уже есть вся информация в нем уничтожается);

w+ (Создать новый пустой файл для чтения записи; если файл с таким именем уже есть вся информация в нем уничтожается);

a (Открыть файл для дозаписи; данные будут записываться в конец файла);

a+ (Открыть файл для дозаписи и чтения данных; данные будут записываться в конец файла);

b (Флаг, указывающий на работу (чтение и запись) с двоичным файлом; указывается только в Windows).

Третий необязательный аргумент use_include_path определяет должны ли искаться файлы в каталоге include_path.

При удачном открытии файла, функция fopen возвращает дескриптор файла, в случае неудачи - false. Дескриптор файла представляет собой указатель на открытый файл, который используется операционной системой для поддержки операций с этим файлом. Возвращенный функцией дескриптор файла необходимо затем указывать во всех функциях, которые в дальнейшем будут работать с этим файлом.

Отображение файлов

Содержимое открытого файла можно отобразить в браузере с помощью функции fpassthru: int fpassthru (int file)

Аргумент file представляет собой дескриптор файла.

<?

$file = fopen("c:/www/html/pavlovo.jpg","rb");

if(!file)

{

echo("Ошибка открытия файла");

}

else

{

fpassthru($file);

}

?>

Для текстовых файлов существует функция отображения readfile: readfile (string filename)

Где filename - имя файла, а не его дескриптор:

<?

readfile ("file.txt");

?>

Закрытие файлов

Закрытие файлов осуществляется с помощью функции fclose: int fclose (int file)

Аргумент file представляет собой дескриптор файла, который необходимо закрыть.

Чтение из файлов

Прочитать строку из открытого файла можно с помощью функции fread:

string fread ( int file, int length )

Эта функция возвращает строку длиной length символов из файла с дескриптором file.

<?

$file = fopen("c:/www/html/file.txt","r");

if(!file)

{

echo("Ошибка открытия файла");

}

else

{

$buff = fread ($file,100);

print $buff;

}

?>

Можно также пользоваться функцией fgets: string fgets ( int file, int length)

Эта функция читает и возвращает строку длиной length - 1 байт. Чтение прекращается, когда достигнута новая строка или конец файла. При достижении конца файла функция возвращает пустую строку.

Для чтения файла с удалением из него тегов HTML применяется функция fgetss:

string fgetss (int file, int length [, string allowable_tags])

Необязательный третий параметр allowable_tags может содержать строку со списком тегов, которые не должны быть отброшены, при этом теги в строке записываются через запятую.

Функция file записывает содержимое файла в массив:

array file (string filename [, int use_include_path])

Функция считывает файл с именем filename и возвращает массив, каждый элемент которого соответствует строке в прочитанном файле. В следующем примере с помощью функции читается файл, информация из которого затем выводится в браузер.

<?

$file_array = file("file.txt");

if(!$file_array)

{

echo("Ошибка открытия файла");

}

else

{

for($i=0; $i < count($file_array); $i++)

{

printf("%s<br>", $file_array[$i]);

}

}

?>

Для чтения файлов с расширением *.csv применяется функция fgetcsv:

array fgetcsv ( int file, int length, char delim)

Функция читает строку из файла и разбивает ее по символу delim. Параметр delim должен обязательно быть строкой из одного символа, иначе принимается во внимание только первый символ этой строки. Функция возвращает получившийся массив или false, если достигнут конец файла. Пустые строки в файле не игнорируются, а возвращаются как массив из одного элемента - пустой строки. Параметр length задает максимальную длину строки точно так же, как это делается в функции fgets.

Формат CSV является одним из форматов, в котором может сохранять файлы MSExcel.

Запись в файлы

Запись в файлы осуществляется функциями fputs и fwrite, которые абсолютно идентичны:

int fputs ( int file, string string [, int length ])

int fwrite ( int file, string string [, int length ])

Первый аргумент - дескриптор файла, в который осуществляется запись. Второй аргумент представляет собой строку, которая должна быть записана в файл. Третий необязательный аргумент задает количество символов в строке, которые должны быть записаны. Если третий аргумент не указан, записывается вся строка.

// Запись в файл строки "Hello, world!"

<?

$file = fopen ("file.txt","r+");

$str = "Hello, world!";

if ( !$file )

{

echo("Ошибка открытия файла");

}

else

{

fputs ( $file, $str);

}

fclose ($file);

?>

Копирование файлов осуществляется функцией copy: int copy ( string file1, string file2)

Функция копирует файл с именем file1 в файл с именем file2. Если файл file2 на момент копирования существовал, то он перезаписывается.

Переименование файла производится с помощью функции rename:

int rename ( string old, string new)

Эта функция переименовывает файл с именем old в файл с именем new.

Удаление файла осуществляется посредством функции unlink:

int unlink ( string filename)

Атрибуты файлов

Для получения дополнительной информации об атрибутах файла используют следующие функции.

Функция file_exists проверяет, существует ли файл и возвращает true, если файл существует и false в противном случае: bool file_exists ( string filename)

Функция fileatime возвращает время последнего обращения к файлу: int fileatime ( string filename)

Функция filemtime возвращает время последней модификации содержимого файла: int filemtime ( string filename)

Функция file_size возвращает размер файла в байтах: int file_size ( string filename)

Функция file_type возвращает тип файла: string file_type ( string filename). Строка, возвращаемая этой функцией, содержит один из следующих типов файла:

char (специальное символьное устройство);

dir (каталог);

fifo (именованный канал);

link (символическая ссылка);

block (специальное блочное устройство);

file (обычный файл);

unknown (тип не установлен).

Для установки текущего каталога применяется функция chdir: int chdir ( string directory)

chdir("/tmp/data"); // переход по абсолютному пути

chdir("./js"); // переход в подкаталог текущего каталога

chdir(".."); // переход в родительский каталог

chdir("~/data"); // переходим в /home/пользователь/data (для Unix)

Узнать текущий каталог можно с помощью функции getcwd: string getcwd ( string path)

Функция opendir используется для открытия каталога, заданный параметром path:

int opendir ( string path)

Для закрытия каталога используют функцию closedir: void closedir ($dir)

// чтение и вывод файлов, находящихся в текущем каталоге.

<?

$dir = opendir (".");

echo "Files:\n";

while ($file = readdir ($dir))

{

echo "$file<br>";

}

closedir ($dir);

?>

Пример на рассмотренные выше функции.

// удаление всех файлов из каталога c:/temp, к которым не было доступа в течение суток.

<?

function delTemporaryFiles ($directory)

{

$dir = opendir ($directory);

while (( $file = readdir ($dir)))

{

if( is_file ($directory."/".$file))

{

$acc_time = fileatime ($directory."/".$file);

$time = time();

if (($time - $acc_time) > 24*60*60)

{

if ( unlink ($directory."/".$file))

{

echo ("Файлы успешно удалены");

}

}

}

else if ( is_dir ($directory."/".$file) && ($file != ".") && ($file != ".."))

{

delTemporaryFiles ($directory."/".$file);

}

}

closedir ($dir);

}

delTemporaryFiles ("c:/temp");

?>

Создать каталог можно с помощью функции mkdir: bool mkdir ( string dirname, int mode)

Эта функция создает каталог с именем dirname и правами доступа mode. В случае неудачи возвращает false.

Удалить каталог можно с помощью функции rmdir: bool rmdir ( string dirname)

Перемещение по файлам

Существует несколько функций, с помощью которых можно управлять положением указателя текущей позиции при чтении данных из файла.

Установка указателя текущей позиции в начало файла производится функцией rewind:

int rewind ( int file)

Аргумент file является дескриптором файла.

Текущее положение указателя - функция ftell: int ftell ( int file)

Установить указатель в любое место файла можно, используя функцию fseek:

int fseek ( int file, int offset [, int whence ])

Функция fseek устанавливает указатель файла на байт со смещением offset (от начала файла, от его конца или от текущей позиции, в зависимости от значения параметра whence). Аргумент file представляет собой дескриптор файла. Аргумент whence задает с какого места отсчитывается смещение offset и может принимать одно из следующих значений:

SEEK_SET (отсчитывает позицию начала файла);(по умолчанию)

SEEK_CUR (отсчитывает позицию относительно текущего положения указателя);

SEEK_END (отсчитывает позицию относительно конца файла).

С помощью функции feof проверяется, находится ли указатель в конце файла: int feof ( int file)

Если указатель находится в конце файла, функция возвращает true, в ином случае возвращается false.

//Использование функцию feof при чтении файла:

<?

$file = fopen ("file.txt","r");

if ($file)

{

while(!feof($file))

{

$str = fgets($file);

echo $str;

echo ("<br>");

}

fclose ( $file);

}

else

{

echo("Ошибка открытия файла");

}

?>

Задания

1. Создайте скрипт, который осуществляет подсчет числа байтов в файлах текущего каталога.

2. Осуществите рекурсивный спуск по каталогу C:/Windows, подсчитав количество файлов в этом каталоге и во всех вложенных каталогах.

3. Создайте текстовый файл, содержащий несколько текстовых строк. Перепишите файл таким образом, чтобы порядок следования строк файле поменялся: первая строка— на последнем месте, вторая— на предпоследнем, ..., последняя — на первом.

4. Откройте любой текстовый файл и удалите из него все пробельные символы.

Функции в PHP

Функцией будем называть фрагмент программного кода, обладающий уникальным именем и предназначенный для решения некоторой конкретной задачи. Функция вызывается по имени, что позволяет многократно выполнять фрагмент с указанным именем.

Определение и вызов функций

В PHP функции могут создаваться в любой точке программ, но рекомендуется разместить все функции, используемые сценарием, в самом начале файла. Существует и другой способ размещения функций - выделение функций в отдельный файл (библиотеку). Библиотеки удобны тем, что их функции можно использовать в разных приложениях, не создавая лишних копий и не рискуя допустить ошибки в процессе копирования.

function имя_функции ([$параметр1,$параметр2, .... $параметрn])

{

тело функции

}

Имя функции является идентификатором функции. После имени функции следуют обязательные круглые скобки, в которые заключается необязательный список входных параметров ($параметр1, $параметр2, .... $параметрn). В PHP указывать тип входных параметров не нужно. После закрывающей круглой скобки следуют фигурные скобки, в которые заключается программный код, ассоциируемый с именем функции.

function display () {

print "Function in PHP";

}

Аргументы функций

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

С помощью аргументов данные в функцию можно передавать тремя различными способами. 1) передача аргументов по значению (используется по умолчанию), 2)по ссылке и 3)задание значения аргументов по умолчанию.

  1. При передаче аргумента в функцию по значению, изменение значения аргумента внутри функции не влияет на его значение вне функции.

<?php ## Передача параметров по значению,

function increment($a) {

echo "Текущее значение: $a<br>";

$а++;

echo "После увеличения: $a<br>";

}

$num = 10;

echo "Начальное значение: $num<br>";

increment ($num);

echo "После вызова функции: $num<br>"; //выведет 10

?>

  1. При передаче аргумента в функцию по ссылке в определении функции перед именем аргумента следует написать знак амперсант «&». Это позволить функции изменять ее аргументы и повлияет на их значения вне функции

<? ## Передача параметров по ссылке .

function increment(&$a) { // $а — ссылочная

echo "Текущее значение: $a<br>";

$а++;

echo "После увеличения: $a<br>";

}

$num = 10;

echo "Начальное значение: $num<br>";

increment($num); // передача по ссылке

echo "После вызова функции: $num<br>"; // выводит 11!

?>

  1. В функции можно определять значения аргументов, используемые по умолчанию. Само значение по умолчанию должно быть константным выражением, а не переменной и не представителем класса или вызовом другой функции.

// Значения аргументов по умолчанию

<?php

function login($pass, $user=”Nick”) { echo $user.”=”.pass; }

login(123);//вызов функции, выведет Nick=123

?>

Если у функции несколько параметров, то те аргументы, для которых задаются значения по умолчанию, должны быть записаны после всех остальных аргументов в определении функции. В противном случае появится ошибка, если эти аргументы будут опущены при вызове функции.

Инструкция return

в РНР можно использовать return абсолютно для любых объектов (какими бы большими они ни были), причем без заметной потери быстродействия. Сразу несколько значений функции, разумеется, возвратить не могут. Простой пример функции, возвращающей квадрат своего аргумента:

function mySqr($n) {

return $n*$n;

}

$value = mySqr(4);

echo $value; // выводит 16

echo mySqr(10); // выводит 100

Если функция не возвращает никакого значения, т. е. инструкции return в ней нет, то считается, что функция вернула null .

<?php ## Неявный возврат NULL.

function f() { }

var_dump(f()); // печатает NULL

?>

Локальные переменные

Переменные, объявленные в теле функции или как аргумент функции, это некоторые временные объекты, которые создаются в момент вызова и исчезают после окончания функции.

<?php ## Локальные переменные,

function silly() {

$i = rand(); // записывает в $i случайное число

echo "$i<br>"; // выводит его на экран

// Эта $i не имеет к глобальной $i никакого отношения!

}

// Выводит в цикле 10 случайных чисел,

for ($i=0; $i!=10; $i++) silly();

?>

Здесь переменная $i в функции будет не той переменной $i, которая используется в программе для организации цикла. Поэтому, собственно, цикл и проработает только 10 "витков", напечатав 10 случайных чисел (а не будет крутиться долго и упорно, пока "в рулетке" функции rand () не выпадет 10).

Глобальные переменные

Если функцие необходимо добраться к глобальной переменной, то в ее теле необходимо до первого использования в своем теле внешней переменной объявить ее "глобальной" при помощи инструкции global:

global $variable;

<?php ## Глобальные переменные в функции.

$monthes = array( 1 => "Январь", 2 => "Февраль", // ... 12 => "Декабрь" ).;

// Возвращает название месяца по его номеру. Нумерация начинается с 1!

function getMonthName($n) {

global $monthes;

return $monthes[$n];

}

// Применение.

echo getMonthName(2); // выводит "Февраль"

?>

Массив $monthes, содержащий названия месяцев, довольно объемный. Поэтому описывать его прямо в функции было бы неудобно — он бы тогда создавался при каждом вызове функции.

Статические переменные

В РНР есть еще один вид переменных - статические. Работают они точно так же, как и в С. Конструкция static сообщает компилятору, что уничтожать указанную переменную для функции между вызовами не надо. В то же время присваивание $count = 0 сработает только один раз, а именно — при самом первом обращении к функции. Рассмотрим пример функции, которая подсчитывает, сколько раз она была вызвана.

<?php ## Статические переменные,

function selfcount() {

static $count = 0;

$count++;

echo $count;

}

for ($i=0; $i<5; $i++) selfcount();

?>

После запуска будет выведена строка 12345. Если убрать слово static, то выведет: 11111. Т.к.переменная $count стала локальной, и при каждом вызове функции ее значение не определено (что воспринимается оператором ++ как 0).

Вложенные функции

Стандарт РНР не поддерживает вложенные функции. Однако он поддерживает нечто, немного похожее на них. Вместо того чтобы, как и у переменных, ограничить область видимости для вложенных функций своими "родителями", РНР делает их доступными для всей остальной части программы, но только с того момента, когда "функция-родитель" была из нее вызвана.

<?php ## Вложенные функции,

function father($a) {

echo $a, "<br>";

function child($b) {

echo $b + 1, "<br>";

return $b * $b;

}

return $а * $а * child($a);

// фактически возвращает $а * $а * ($а+1) * ($а+1)

}

// Вызываем функции.

father(10);

child(30);

?>

Если вызвать их в обратном порядке, это приведет к ошибке.

Рекурсия

В РНР поддерживаются рекурсивные вызовы функций, т. е. вызовы функцией самой себя .

Рассмотрим пример рекурсивной функции — факториал из некоторого числа n (обозначается n!), равный значению 2*3*4*...*n.

function factor($n) {

if ($n <= 0) return 1; //условие выхода из рекурсии

else return $n * factor($n — 1); //рекурсивный вызов

echo factor(20) ;

}

Возврат функцией ссылки

До сих пор мы рассматривали только функции, которые возвращают определенные значения — копии величин, использованных в инструкции return. Если задействовать return &$a, то появится сообщение о синтаксической ошибке (РНР воспринимает & только в правой части оператора присваивания сразу после знака =). Для описания функции, возвращающей ссылку, воспользуемся специальным синтаксисом описания.

<?php ## Возврат ссылки.

$а = 314;

function &R() { // & — возвращает ссылку

global $a; // объявляет $а глобальной

return $a; // возвращает, ссылку, а не значение!

}

$b =& R(); // не забудьте & !!!

$Ь = 0; // в действительности присваивает 0 переменной $а

echo $а; // выводит 0, это значит, что теперь $Ь — синоним $а

?>

Т.е. нужно поставить & в двух местах: перед определением имени функции, а также в правой части оператора присваивания при вызове функции. Использовать амперсанд в инструкции return не нужно.

Задание

Описать рекурсивную функцию PowerN(x,n) , находящую значение n-й степени числа x по формуле: x0 = 1, xn = x·xn–1 при n > 0, xn = 1 / x–n при n < 0. С помощью этой функции найти значения X^N при 5 различных значениях N для данного X.

Протокол HTTP

HTTP (HyperText Transfer Protocol, протокол передачи гипертекста) – это протокол прикладного уровня, разработанный для обмена гипертекстовой информацией в Internet.HTTP предоставляет набор методов для указания способа передачи запроса серверу.

HTTP используется для коммуникаций между различными пользовательскими программами и программами-шлюзами, предоставляющими доступ к существующим Internet-протоколам, таким как SMTP (протокол электронной почты), NNTP (протокол передачи новостей), FTP (протокол передачи файлов), Gopher и WAIS. HTTP разработан для того, чтобы позволять таким шлюзам через промежуточные программы-серверы (proxy) передавать данные без потерь.

Всякая связь между клиентом и сервером осуществляется посредством сообще­ний. HTTP различает только два вида сообщений — сообщения-запросы и сооб­щения-ответы. Как показано на рис. 11.5, а, сообщения-запросы состоят из трех частей. Строка запроса (request line) имеет стандартный вид и определяет опера­цию, которую клиент хочет выполнить на сервере, а также ссылку на документ, связанный с запросом. Отдельное поле требуется для указания версии HTTP, ко­торую использует клиент. В качестве операций(методов) могут быть указаны GET, POST, HEAD, PUT, DELETE и другие. В качестве ссылки чаще всего используется URL-адрес ресурса.

Ответное сообщение начинается строкой состояния (status line), содержащей номер версии и код состояния из трех цифр, как показано на рис. 11.5, б. Код кратко поясняется текстовой фразой, которая также является частью строки со­стояния. Так, например, код состояния 200 указывает на то, что запрос был обра­ботан и имеет ассоциированную с ним фразу «ОК». Вот другие часто используе­мые коды:

400 (Bad Request)

403 (Forbidden)

404 (Not Found)

Сообщения с запросами или ответами могут содержать дополнительные за­головки. Так, например, если клиент отправляет запрос на операцию post с до­кументом, предназначенным только для чтения, сервер отвечает сообщением с кодом состояния 405 (Method Not Allowed) и заголовком сообщения Allow, опре­деляющим допустимые операции (например, head и get). Другой пример: клиент может поинтересоваться, не изменялся ли документ с определенного момента вре­мени Т. В этом случае клиент отправляет запрос get, дополненный заголовком сообщения If-Modified-Sincе с определенным значением Т.

Методы

Любой запрос клиента к серверу должен начинаться с указания метода. Метод сообщает о цели запроса клиента. Протокол HTTP поддерживает достаточно много методов, но в основном используются только три: POST, GET и HEAD. Метод GET позволяет получить любые данные, идентифицированные с помощью URI в запросе ресурса. Если URI указывает на программу, то возвращается результат работы программы, а не ее текст. Дополнительная информация, необходимая для обработки запроса, встраивается в сам запрос (в строку статуса). При использовании метода GET в поле тела ресурса возвращается собственно затребованная информация.

Метод HEAD используют для получения информации о ресурсе.

Метод POST разработан для передачи на сервер такой информации, как новостные и почтовые сообщения, данные для добавления в базу данных, т.е. для передачи информации большого объема и достаточно важной. В отличие от методов GET и HEAD, в POST передается тело ресурса, которое и является информацией, получаемой из полей форм или других источников ввода.

Использование HTML-форм для передачи данных на сервер

Для передачи данных на сервер в языке HTML есть специальная конструкция – формы. Формы предназначены для того, чтобы получать от пользователя информацию. Формы применяются для ввода пользователем информации. В них можно вводить текст или выбирать подходящие варианты из списка. Данные, записанные в форму, отправляются для обработки специальной программе (например, скрипту на PHP) на сервере. В зависимости от введенных пользователем данных эта программа может формировать различные web-страницы, отправлять запросы к базе данных, запускать различные приложения и т.п.

При отправке данных формы с помощью метода GET содержимое формы добавляется к URL после знака вопроса в виде пар имя=значения, объединенных с помощью амперсанда &:

url?name1=value1&name2=value2&name3=value3

Здесь url – это URL-адрес программы, которая должна обрабатывать форму. Имена name1, name2, name3 соответствуют именам элементов формы, а value1, value2, value3 – значениям этих элементов. Все специальные символы, включая = и &, в именах или значениях этих параметров будут опущены. Поэтому не стоит использовать в названиях или значениях элементов формы эти символы и символы кириллицы в идентификаторах.

Для полей ввода текста и пароля, значением будет то, что введет пользователь. Если пользователь ничего не вводит в такое поле, то в строке запроса будет присутствовать элемент name=, где name соответствует имени этого элемента формы.

Для кнопок типа checkbox и radio button значение value определяется атрибутом VALUE в том случае, когда кнопка отмечена. Не отмеченные кнопки при составлении строки запроса игнорируются целиком. Несколько кнопок типа checkbox могут иметь один атрибут NAME (и различные VALUE), если это необходимо. Кнопки типа radio button предназначены для одного из всех предложенных вариантов и поэтому должны иметь одинаковый атрибут NAME и различные атрибуты VALUE.

В передачи данных методом GET есть один существенный недостаток – любой может подделать значения параметров. Поэтому не советуем использовать этот метод для доступа к защищенным паролем страницам, для передачи информации, влияющей на безопасность работы программы или сервера. Кроме того, не стоит применять метод GET для передачи информации, которую не разрешено изменять пользователю.

При передаче данных методом POST содержимое формы кодируется точно так же, как для метода GET , но вместо добавления строки к URL содержимое запроса посылается блоком данных как часть операции POST. Если присутствует атрибут ACTION, то значение URL, которое там находится, определяет, куда посылать этот блок данных. Этот метод рекомендуется для передачи больших по объему блоков данных.

Информация, введенная пользователем и отправленная серверу с помощью метода POST, подается на стандартный ввод программе, указанной в атрибуте action, или текущему скрипту, если этот атрибут опущен. Длина посылаемого файла передается в переменной окружения CONTENT_LENGTH, а тип данных – в переменной CONTENT_TYPE.

Передать данные методом POST можно только с помощью HTML-формы, поскольку данные передаются в теле запроса, а не в заголовке, как в GET. Соответственно и изменить значение параметров можно, только изменив значение, введенное в форму. При использовании POST пользователь не видит передаваемые серверу данные.

Основное преимущество POST запросов – это их большая безопасность и функциональность по сравнению с GET-запросами. Поэтому метод POST чаще используют для передачи важной информации, а также информации большого объема.

При отправке данных на сервер любым методом передаются не только сами данные, введенные пользователем, но и ряд переменных, называемых переменными окружения, характеризующих клиента, историю его работы, пути к файлам и т.п. Вот некоторые из переменных окружения:

REMOTE_ADDR – IP-адрес хоста (компьютера), отправляющего запрос;

REMOTE_HOST – имя хоста, с которого отправлен запрос;

HTTP_REFERER – адрес страницы, ссылающейся на текущий скрипт;

REQUEST_METHOD – метод, который был использован при отправке запроса;

QUERY_STRING – информация, находящаяся в URL после знака вопроса;

SCRIPT_NAME – виртуальный путь к программе, которая должна выполняться;

HTTP_USER_AGENT – информация о браузере, который использует клиент

Обработка запросов в PHP

Для обращения к переменным, переданным с помощью HTTP-запросов, исполдьзуется специальный массив – $_REQUEST. Этот массив содержит данные, переданные методами POST и GET, а также с помощью HTTP cookies. Это суперглобальный ассоциативный массив, т.е. его значения можно получить в любом месте программы, используя в качестве ключа имя соответствующей переменной (элемента формы).

Допустим, мы создали форму для регистрации участников конференции по программирования, содержащую поля first_name, last_name, title_paper, section. Тогда скрипт, обрабатывающем эту форму, может быть следующий:

<?php

$str = "Здравствуйте,

".$_REQUEST["first_name"]. "

".$_REQUEST["last_name"]."! <br>";

$str .="Вы зарегистрировались на конференцию в секцию ".$_REQUEST["section "]." С докладом ".$_REQUEST["title_paper "] ;

echo $str;

?>

Тогда, если в форму мы ввели имя «Вася», фамилию «Петров» и выбрали среди всех секций секцию РНР и ввели название доклада “Обработка запросов в РНР”, на экране браузера получим такое сообщение:

Вася Петров!

Вы зарегистрировались на конференцию в секцию РНР С докладом Обработка запросов в РНР.

Есть также суперглобальные массивы $_POST и $_GET, содержащие параметры, переданные по POST и GET запросам соответственно.

Приведем пример использования этих массивов. Допустим, нам нужно обработать форму, содержащую элементы ввода с именами first_name, last_name, title_paper, section. Данные были переданы методом POST, и данные, переданные другими методами, мы обрабатывать не хотим. Это можно сделать следующим образом:

<?php

$str = "Здравствуйте,

".$_POST["first_name"]. "

".$_POST["last_name"]."! <br>";

$str .="Вы зарегистрировались на конференцию в секцию ".$_POST ["section "]." С докладом ".$_POST["title_paper "] ;

echo $str;

?>

Для того, чтобы сохранить возможность обработки скриптов более ранних версий, чем PHP5, была введена директива register_globals, разрешающая или запрещающая доступ к переменным непосредственно по их именам. Если в файле настроек PHP параметр register_globals=On, то к переменным, переданным серверу методами GET и POST, можно обращаться просто по их именам (т.е. можно писать $first_name). Если же register_globals=Off, то нужно писать $_REQUEST["first_name"] или $_POST["first_name"], $_GET["first_name"], $HTTP_POST_VARS["first_name"], $HTTP_GET_VARS["first_name"]. С точки зрения безопасности эту директиву лучше отключать (т.е. register_globals=Off). При включенной директиве register_globals перечисленные выше массивы также будут содержать данные, переданные клиентом.

Иногда возникает необходимость узнать значение какой-либо переменной окружения, например метод, использовавшийся при передаче запроса или IP-адрес компьютера, отправившего запрос. Получить такую информацию можно с помощью функции getenv(). Она возвращает значение переменной окружения, имя которой передано ей в качестве параметра.

<?

getenv('REQUEST_METHOD');

// возвратит использованный метод

echo getenv ('REMOTE_ADDR');

// выведет IP-адрес пользователя, пославшего запрос

?>

При использовании метода GET, данные передаются добавлением строки запроса в виде пар «имя_переменной=значение к URL-адресу ресурса». Все, что записано в URL после знака вопроса, можно получить с помощью команды getenv('QUERY_STRING');

Задание

Создать форму для регистрации на форуме. На форуме обсуждается определенный набор тем. Форма регистрации должна содержать следующие поля: фамилия, имя, ник, год рождения, пол, пароль. А также список тем, обсуждаемых на форуме.

При регистрации новый пользователь должен обязательно заполнить все поля и выбрать одну или более тем.

Форма также должна содержать 2 кнопки: Зарегистрироваться и Отмена. При нажатии на кнопку «Зарегистрироваться» происходи проверка введенных данных, если данные введены корректно, то переход на следующую страницу приветствия в виде: ФАМИЛИЯ ИМЯ, Вы зарегистрировались на форуме по ником НИК и можете посещать следующие темы: СПИСОК ТЕМ.

COOKIES

Cookies - это текстовые строки, хранящиеся на стороне клиента, и содержащие пары "имя-значение", с которыми связан URL, по которому браузер определяет нужно ли посылать cookies на сервер.

Установка cookies производится с помощью функции setcookie:

bool setcookie (string name [, string value [, int expire [, string path [, string domain [, int secure]]]]]),

где name - имя устанавливаемого cookie;

value - значение, хранящееся в cookie с именем $name;

expire - время в секундах с начала эпохи, по истечение которого текущий cookie становится недейтвительным;

path - путь, по которому доступен cookie;

domain - домен, из которого доступен cookie;

secure - директива, определяющая, доступен ли cookie не по запросу HTPPS. По умолчанию эта директива имеет значение 0, что означает возможность доступа к cookie по обычному запросу HTTP.

// подсчет при помощи cookies количество обращений посетителя к странице.

<?

$counter++;

setcookie("counter",$counter);

echo("Вы посетили эту страницу $counter раз");

?>

Результат выполнения сценария количество посещений данной страницы.

При работе с cookies необходимо учитывать, что cookie надо обязательно устанавливать перед отправкой в браузер каких-либо заголовков, поскольку сами cookies устанавливаются в виде заголовков. Поэтому если установить cookies после какого-либо текста, отправляемого в браузер, то возникнет ошибочная ситуация.

//текст перед установкой cookie

<?

$counter++;

echo("Вы посетили эту страницу ”);

setcookie("counter",$counter);

echo(" $counter раз");

?>

При выполнении этого сценария выводится сообщение об ошибке, т.к. перед установкой cookie находился текст.

Значение, хранящееся в cookie можно получить через глобальный массив $_COOKIE["name"]:

<?

$_COOKIE['counter']++;

setcookie("counter",$_COOKIE['counter']);

echo 'Вы посетили эту страницу '.$_COOKIE['counter'].' раз';

?>

Т.к. некоторые пользователи отключают cookie в настройках своих браузеров, для корректной работы, в приложение, использующее cookies, необходимо помещать код, проверяющий включены ли cookies у посетителя, и, если нет, то сообщающий ему о необходимости включить cookie:

<?

if(!$cookie)

{

/* посылаем заголовок переадресации на страницу,

с которой будет предпринята попытка установить cookie */

header("Location: $PHP_SELF?cookie=1");

/* устанавливаем cookie с именем "test" */

setcookie("test","1");

}

else

{

if(!$test)

{

echo("Для корректной работы приложения необходимо включить cookies");

}

else

{

/* cookie включены, переходим на нужную страницу */

header("Location: http://localhost/test1.php");

}

}

?>

Установка срока годности cookies

По умолчанию cookies устанавливаются на один сеанс работы с браузером, однако можно задать для них более продолжительный срок существования. Срок годности устанавливается в секундах относительно начала эпохи. В PHP существуют функции time и mktime для работы с датой и временем, позволяющие переводить текущее время в количество секунд с начала эпохи. Функция time просто переводит текущее системное время в количество секунд, прошедших с начала эпохи: time();

Усовершенствованным вариантом функции time является функция mktime:

int mktime ([int hour [, int minute [, int second [, int month [, int day [, int year [, int is_dst]]]]]]])

//установка срока годности cookies:

<?

/* этот cookie действителен в течение 10 мин после создания */

setcookie("name", $value, time() + 600);

/* действие этого cookie прекращается в полночь 25 января 2010 года */

setcookie("name", $value, mktime(0,0,0,01,25,2010));

/* действие этого cookie прекращается в 18.00 25 января 2010 года */

setcookie("name", $value, mktime(18,0,0,01,25,2010));

?>

Удаление cookie

Для удаления cookie надо вызвать функцию setcookie и передать ей имя того cookie, который подлежит удалению: setcookie("name"). Другие установленные cookie при этом не удаляются.

Проверить, установлены ли cookie с заданным именем, используют функцию isset(name)

<?php

if (isset($_COOKIE["user"]))

echo "Welcome " . $_COOKIE["user"] . "!<br />";

else

echo "Welcome guest!<br />";

?>

Задание.

  1. Создайте скрипт, сохраняющий в cookie массив, в том числе многомерный, не прибегая к его упаковке в строку.

  2. С помощью механизма cookie хранить информацию о вошедшем пользователе на форум из задания в Лекции №9.

Сессии

Сессии предназначены для хранения сведений о пользователях при переходах между несколькими страницами. При использовании сессий данные сохраняются во временных файлах на сервере.

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

Протокол HTTP не имеет встроенного способа сохранения состояния между двумя транзакциями. Т. е., когда пользователь открывает сначала одну страницу сайта, а затем переходит на другую страницу этого же сайта, то основываясь только на средствах, предоставляемых протоколом HTTP невозможно установить, что оба запроса относятся к одному пользователю. Т. о. необходим метод, при помощи которого было бы отслеживать информацию о пользователе в течение одного сеанса связи с Web-сайтов. Сеанс представляет собой группу переменных, которые, в отличие от обычных переменных, сохраняются и после завершения выполнения PHP-сценария.

  1. Открытие сессии заключается в использовании функции session_start, которая вызывается в начале PHP-сценария: session_start();

Эта функция проверяет, существует ли идентификатор сессии, и, если нет, то создает его. Если идентификатор текущей сессии уже существует, то загружаются зарегистрированные переменные сессии.

  1. После инициализации сессии можно сохранять информацию в суперглобальном массиве $_SESSION.

<?php

// Инициируем сессию

session_start();

// Помещаем значение в сессию

$_SESSION['name'] = "value";

// Помещаем массив в сессию

$arr = array("first", "second", "third");

$_SESSION['arr'] = $arr;

// Выводим ссылку на другую страницу

echo "<a href='other.php'>другая страница</a>";

?>

  1. Извлечение значения сессионных переменных можно из суперглобального массива $_SESSION.

<?php

// Инициируем сессию

session_start();

// Выводим содержимое суперглобального массива $_SESSION

echo "<pre>";

print_r($_SESSION);

echo "</pre>";

?>

Результат работы скрипта выглядит следующим образом:

Array

(

[name] => value

[arr] => Array

(

[0] => first

[1] => second

[2] => third

)

)

  1. Закрытие сессии

После завершения работы с сессией сначала нужно разрегистрировать все переменные сессии, вызвав функцию unset(): unset($_SESSION["username"]);

А после, удалить сессию вызовом функции session_destroy();

Задание.

  1. Модифицируйте систему определения посетителей online таким образом, чтобы в таблицу session помещалась информация об IP-адресе посетителя, а сама система имела возможность запретить просмотр ресурса сайта с определенного IP-адреса.

  2. С помощью механизма session хранить информацию о вошедшем пользователе на форум из задания в Лекции №9.

Классы и сокрытие данных

Ранние версии РНР (вплоть до версии 5) поддерживали объектно-ориентированный подход на недостаточно удовлетворительном уровне. Теперь язык поддерживает объектный подход в достаточной для практического применения степени. Теперь все переменные хранят не объекты, а лишь ссылки на них. Во время копирования таких переменных копируются лишь ссылки, но не сами объекты. Средства для сокрытия данных внутри класса (ключевые слова private, public и protected). Механизм поддержки интерфейсов. Интерфейсы можно в первом приближении рассматривать как средства для обеспечения множественного наследования классов. Поддержка исключений. Деструкторы, автоматически вызываемые при удалении объекта из памяти. Перегрузка операций присваивания значений свойствам объекта, получения значения свойства и вызова несуществующего метода.

Ключевым понятием ООП является класс. Класс можно рассматривать как тип некоторой переменной. Переменная класса (далее будем ее называть объектом класса) обычно имеет набор свойств (значений различных типов) и операций (или методов, функций), которые могут быть с ним проведены. Свойства и методы класса часто называют его членами. Так же, как может существовать много переменных одного и того же типа (например, строкового), не связанных между собой, возможно и наличие в программе множества объектов одного и того же класса, различающихся своими свойствами.

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

Создание нового класса

Новый класс (тип данных) в программе описывается при помощи ключевого слова class. Внутри класса могут располагаться его свойства (переменные класса) и методы (функции-члены класса).

//пример класса комплексного числа

<?php ## Пример класса,

class Math_Complex {

public $re, $im; // Свойства: действительная и мнимая части,

function add($re, $im) { // Метод: добавить число к текущему значению.

$this->re += $re;

$this->im += $im;

}

?>

Переменная $this всегда существует внутри методов (функций-членов) класса. С ее помощью можно ''добраться" до свойств объекта, для которого вызван метод.

Создание объекта некоторого класса

При создании объектов класса, применяется ключевое слово new, за которым следует имя класса:

$obj = new Math_Complex;

Теперь $obj хранит все данные класса — в частности, содержит внутри себя отдельные значения $ге и $im.

Доступ к свойствам объекта

Каждый объект имеет свой собственный набор ассоциированных с ним свойств (значений, или переменных) и множество методов (функций- членов). Каждое свойство объекта доступно в программе по его имени. Можно присваивать значение свойству или получать его величину:

// Создаем новый объект класса Math_Complex.

$obj = new Math_Complex;

// Присваивает значение свойствам $ге и $im объекта $obj.

$obj->re = 6;

$obj->im = 10;

// Выводит значение свойства re объекта $obj.

echo $obj->re;

Доступ к свойству осуществляется при помощи оператора -> (стрелка, символ -, за которым идет >).

Доступ к методам

В РНР для вызова метода некоторого объекта используется оператор "стрелка" .

<?php ## Вызов метода объекта.

// Подключение каталога библиотек в include_path.

require_once "lib/config.php";

// Загрузка класса.

require_once "Math/Complex.php";

// Создаем новый объект класса Math_Complex.

$obj = new Math_Complex;

// Присваиваем начальное значение свойствам.

$obj->re = 16.7;

$obj->im = 101;

// Вызов метода add()c параметрами (18.09, 303) объекта $obj.

$obj->add(18.09/ 303);

// Выводим результат:

echo "({$obj->re}, {$obj->im})";

?>

Переопределить арифметические операторы (например, +, - и т. д.) для объектов в РНР нельзя .

Создание нескольких объектов

В качестве параметра функции можно указывать объект другого (или того же самого) класса.

<?php ## Пример класса с методом,

class Math_Complex {

public $re, $im;

// Добавляет к текущему комплексному числу другое,

function add(Math_Complex $y) {

$this->re += $y->re;

$this->im += $y->im;

}

// Преобразует число в строку (например, для вывода).

function __toString() {

return "({$this->re}, {$this->im})";

}

}

?>

Мы явно указали перед параметром $у тип Math_Complex. Это говорит РНР, что мы можем передавать в данную функцию только объекты этого класса, но не другого. Указывать типы аргументов можно с пятой версии РНР. Например, при попытке указать вместо $у целое число мы получим ошибку во время исполнения программы:

$obj->add(1);

Fatal error: Argument 1 must be an object of class Math_Complex

В отличие от таких языков, как C++ и Java, в РНР не поддерживается создание в одном классе нескольких методов с одинаковым именем, которые бы различались только типами и количеством аргументов.

Перегрузка преобразования в строку

В РНР существует ряд имен методов, начинающихся с двойных подчерков, которые имеют специальное значение. Функция __tostring() вызывается РНР автоматически всякий раз, когда мы затребуем неявное преобразование ссылки на объект в строку.

Конструктор

Для определения конструктора класса используют метод с названием __construct(). Конструктор вызывается всякий раз, когда вы используете оператор new для объекта. В РНР у класса может быть только один конструктор.

<?php ## Пример класса с конструктором,

class Math_Complex2 {

public $re, $im;

// Инициализация нового объекта,

function __construct($re, $im) {

$this->re = $re;

$this->im = $im;

}

}

//создание объекта с помощью конструктора

$a = new Math_Complex2(314, 101);

?>

Параметры по умолчанию

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

function __construct($re=0, $im=0) {

$this->re = $re;

$this->im = $im; }

мы заставим РНР корректно воспринимать следующие четыре команды:

$а = new Math_Complex2;

$а = new Math_Complex2();

$а = new Math_Complex2(101);

$a - new Math_Complex2(101, 303);

При этом недостающие параметры будут заполнены значениями по умолчанию.

Деструктор

При использовании объектов возникает проблема корректного освобождения ресурсов. Это объясняется тем, что объект при работе может использовать не только свои собственные свойства, но также и другие объекты, а также, что самое важное, различные внешние ресурсы (файлы, потоки, соединения с СУБД и т. д.).

Деструктор — специальный метод объекта, который вызывается при уничтожении этого объекта (например, после завершения программы). Деструкторы обычно выполняют служебную работу — закрывают файлы, записывают протоколы работы, разрывают соединения, освобождают ресурсы. В ранних версиях РНР, включая РНР 4, деструкторы не поддерживались. Деструктор — это специальный метод класса с именем __destruct(), который будет гарантированно вызван при потере последней ссылки на объект в программе. Так как деструктор запускается самим РНР, он не должен принимать никаких параметров.

Права доступа к членам класса

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

Чаще всего стараются не делать открытыми свойства класса, предоставляя доступ к ним только через специальные методы. Так можно, например, запретить в программе изменение того или иного свойства.

Модификаторы доступа

В отличие от РНР 4, в РНР версии 5 существуют три модификатора ограничения доступа: public, protected и private. Их можно указывать перед описанием метода или свойства класса.

  1. public: открытый доступ. Члены класса, помеченные ключевым словом public, доступны для использования извне класса (например, из вызывающей программы).

class Hotel {

public $exit;

public function escape() {

echo "Let's go through the {$this->exit}!";

}

}

$theLafayette = new Hotel();

$theLafayette->exit = "main wet wall"; // допустимо

$theLafayette->escape(); // допустимо

В РНР по умолчанию подразумевается модификатор public. Таким образом, если вы не укажете никакого модификатора при описании метода или свойства (например, воспользуетесь ключевым словом var), член класса будет доступен для вызывающей программы.

  1. Private: доступ только из методов класса. С использованием ключевого слова private ( "закрытый") вы можете сделать члены касса "невидимыми" из вызывающей программы, будто бы их и нет. В то же время, методы "своего" класса могут обращаться к ним без всякого ограничения.

class Hotel {

private $exit;

public function escape() {

$this->findWayOut(); // допустимо

echo "Let's go through the {$this->exit}!"; // допустимо

}

public function lock() { $this->exit = null; }

private function findWayOut() {

$this->exit = "main wet wall"; //допустимо

}

}

$theLafayette = new Hotel();

$theLafayette->findWayOut(); // Ошибка! Доступ закрыт!

$theLafayette->escape(); // допустимо

$theLafayette->exit = "hotel doors"; // Ошибка! Доступ закрыт!

Модификатор private включает максимально возможные ограничения на доступ к членам класса. Он разрабатывался специально для того, чтобы запретить прямое изменение свойств объекта, а также доступ к различным служебным методам.

Существует один интересный прием применения private-методов класса — это объявление конструктора или деструктора "личным". При наличии private-конструктора объекты класса нельзя будет создать из вызывающей программы, зато это можно делать из какого-нибудь метода класса. Соответственно, объект, имеющий private-деструктор, не может быть уничтожен ниоткуда, кроме как из одного из членов класса — иначе возникнет ошибка во время выполнения программы.

  1. Protected: доступ из методов производного класса. Модификатор protected ("защищенный") с точки зрения вызывающей программы выглядит точно так же, как и private: он запрещает доступ к членам объекта извне. Однако по сравнению с private он позволяет обращаться к членам не только из "своих" методов, но также и из методов производных классов (если используется наследование). "защищенными" обычно делают лишь методы, но не свойства классов.

Статические члены класса

При использовании классов и объектно-ориентированного подхода также можно создавать статические члены класса. Такие члены существуют в единственном экземпляре и разделяются всеми экземплярами (объектами) одного и того же класса. В этом и заключается весь смысл их существования.

Статическое свойство класса недоступно через обращение $this->property или $obj‑>property. Вместо этого следует использовать немного необычный синтаксис:

ИмяКласса: :$property или self: : $property(при вызове из метода класса).

Статический метод во время своего запуска не получает ссылку $this, поэтому он может работать только со статическими членами (свойствами и другими методами) своего класса.

// класс, который "считает", сколько его экземпляров существует в текущий момент

<?php ## Использование статических членов класса,

class Counter {

// Скрытый статический член класса — общий для всех объектов,

private static $count = 0;

// Конструктор увеличивает счетчик на 1.

public function __construct() { self::$count++; }

// Деструктор же — уменьшает.

public function __destruct() { self::$count—; }

// Статическая функция, возвращает счетчик объектов,

public static function getCount() { return self::$count; }

)

// Создаем б объектов.

for ($objs=array(), $i=0; $i<6; $i++)

$objs[] = new Counter();

echo "Сейчас существует {$objs[0]->getCount()} объектов.<br>";

// Удаляем один объект.

$objs[5] = null;

// Счетчик объектов уменьшится!

echo "А теперь — {$objs[0]->getCount()} объектов.<br>";

// Удаляем все объекты.

$objs = array();

// Другой способ вызова статического метода — с указанием класса.

// Это очень похоже на вызов функции из библиотеки,

echo "Под конец осталось — ".Counter::getCount()." объектов.<br>";

?>

Задание

Создать для задания из Лекции№9 классы User(для клиента, который регистрируется на форуме), Subject(для тем форума с краткой аннотацией к каждой), Message(класс для сообщения, содержащий такие поля, как сообщение, пользователь, время отправки). Снабдить каждый класс необходимыми функциями. Протестировать на примеры из Лекции№9.

Наследование и виртуальные методы

Наследование — одно из основных понятий ООП. При помощи механизма наследования вы можете создавать новые типы данных взяв за основу некоторый уже существующий класс, который в этом случае называют базовым (base class). Получившийся же класс носит имя производного (derived class).

Наследование в ООП используется для нескольких различных целей.

  1. Добавление в существующий класс новых методов и свойств или замена уже существующих. При этом "старая" версия класса уже не будет использоваться; ценность представляет именно новый, расширенный класс.

  2. Наследование в целях классификации и обеспечения однотипности поведения различных классов. Новый, производный класс обладает теми же самыми "особенностями", что и базовый, и может использоваться везде вместо последнего.

Расширение класса

Первый самый простой пример использования наследования — добавление в уже существующий класс новых свойств и методов.

<?php ## Базовый класс,

class File_Logger {

public $f; // открытый файл

public $name; // имя журнала

public $lines = array(); // накапливаемые строки

public $t;

public function _construct($name, $fname) {

$this->name = $name;

$this->f = fopen($fname/ "a+");

}

public function _destruct() {

fputs($this->f, join("", $this->lines));

fclose($this->£);

}

public function log($str) {

$prefix = "[".date("Y-m-d_h:i:s ")."{$this->name}] ";

$str = preg_replace('/A/m', $prefix, rtrim($str));

$this->lines[] = $str."\n";

}

}

?>

Допустим, что действия этого класса нас не совсем устраивают, например, он выполняет большинство функций, необходимых нам, но не реализует некоторых других. Например, предположим, что мы хотим не просто записывать в файл журнала сообщение, но также и сохранять, в каком файле и на какой строке оно было сгенерировано . Зададимся целью создать новый класс File_Logger_Debug, расширяющий возможности класса File_Logger. Он будет добавлять ему несколько новых свойств и методов. Расширяемый класс указывается после ключевого слова extends .

Наследование

<?php ## Наследование.

class File_Logger_Debug extends File_Logger

{

public function _construct($fname) {

//вызов конструктора базового класса

parent::_construct(basename($fname), $fname) ;

}

// Добавляем новый метод,

public function debug($s, $level=0) {

$stack = debug_backtrace();

$file = basename($stack[$level]['file']);

$line = $stack[$level]['line']; I

// Вызываем функцию базового класса.

$this->log(“[at $file line $line] $s”);

}

// Все остальные методы и свойства наследуются автоматически!

}

Класс File_Logger_Debug содержит те же самые свойства и методы, что и File_Logger, но помимо них и еще некоторые дополнительные, "свои". Теперь "часть File_Logger" находится прямо внутри Класса File_Logger_Debug и может быть легко доступна, наравне с методами и свойствами самого класса File_Logger_Debug. Для объекта $logger класса File_Logger_Debug допустимы выражения $logger->debug() И $logger->log() без каких бы то ни было функций-посредников.

Переопределение методов

Под переопределением метода подразумевается его описание в производном классе, в то время как в базовом он уже имеется.

Если вы переопределяете некоторый метод или свойство в производном классе, то должны указать у него такой же модификатор доступа, либо менее строгий. Например, при переопределении private-функции допускается объявлять ее как protected или public. Наоборот, если в базовом классе присутствует public-метод, то в производном он тоже должен иметь модификатор public, в противном случае РНР выдаст сообщение об ошибке.

Доступ к методом базового класса

При вызове функции базового класса используется особый синтаксис с ключевым словом parent, например: parent::_ construct(...);

Финальные методы

При написании метода вы можете явно запретить его переопределение в производных классах, используя модификатор final.

<?php ## Финальные методы,

class Base {

public final function test() {}

}

class Derive extends Base {

public function test() {} // Ошибка! Нельзя переопределить!

}

?>

Запрет наследования

В РНР, как и в Java, можно не только запретить переопределение методов, но и запретить наследование от указанного класса вообще. Для этого ключевое слово final необходимо поставить перед определением класса

final class Base {}

// Теперь нельзя создавать классы, производные от Base.

Используйте final при описании класса только в тех случаях, когда это абсолютно необходимо, и вы уверены, что наследование к классу неприменимо.

Полиморфизм

Полиморфизм — это способность объекта использовать методы не своего собственного класса, а производного, даже если на момент определения базового класса производный еще не существует.

Обычно при объяснении полиморфизма демонстрируют пример программы, выводящей различные геометрические фигуры (круги, квадраты, треугольники и т. д.) и позволяющей однотипно ими манипулировать (изменять размеры, передвигать и т. д.). С использованием полиморфизма вы можете писать классы-шаблоны, реализующие некоторую функциональность лишь частично, и лишь в той степени, в которой она им самим "известна". В дальнейшем, создавая производные классы, вы можете уточнить остальную часть кода, специфичную для вашего приложения. Пусть в программе имеется класс shape, соответствующий некоторой геометрической фигуре. Программа должна уметь выполнять два действия: 1)перемещать фигуры при вызове метода moveBy(); 2) увеличивать или уменьшать размер фигуры с вызовом метода resizeBy().

Мы не уточняем, какой именно фигуре (квадрату, кругу, треугольнику и т. д.) соответствует объект shape. Мы хотим свободно добавлять все новые типы фигур (square, circle, Triangle), ведущие себя похожим образом и удовлетворяющие все тем же жестким требованиям.

<?php ## Базовый класс — геометрическая фигура,

class Shape {

// Любая фигура имеет координаты центра, а также масштаб.

private $х=0, $у=0, $scale=1.0;

// Конструктор класса. Отображает фигуру на экране.

public function _construct() {

$this->show() ;

}

// Деструктор класса. Стирает фигуру с экрана,

public function _destruct() {

$this->hide();

}

// Переместить фигуру на ($dx, $dy) точек,

public final function moveBy($dx, $dy) {

// Вначале стираем фигуру с экрана.

$this->hide();

// Затем изменяем координаты.

$this->x += $dx;

$this->y += $dy;

// Наконец, выводим фигуру на новом месте.

$this->show();

}

// Изменить масштаб отображения фигуры,

public final function resizeBy($coef) {

$this->hide();

$this->scale *= $coef;

$this->show();

}

// Методы возвращают координаты центра и масштаб.

public final function getCoord() { return array($this->x, $this->y); }

public final function getScale() { return $this->scale; }

protected function hide() {

die();

}

protected function show() {

die();

}

}

?>

Для гарантии того, что все геометрические фигуры будут вести себя одинаково, мы объявляем public методы финальными (final). Таким образом, их уже нельзя будет переопределить в производных классах, а значит, фигуры не смогут вести себя по другому.

Виртуальные методы

Виртуальным называют метод, который может переопределяться в производном классе. А в нашем случае функции show() и hide() являются виртуальными, и даже более того: в классе shape мы не знаем, как они должны быть "устроены", потому что у нас еще нет информации о типе фигуры. Таким образом, вызывать виртуальные методы shape бессмысленно.

Виртуальные методы базового класса, которые бессмысленно и даже запрещено вызывать непосредственно, называют абстрактными.

В базовом классе shape виртуальные методы show() и hide() "вырождены" и являются абстрактными, нам обязательно нужно переопределить их в производном классе.

<?php ## Производный класс: фигура-круг.

class Circle extends Shape {

private $radius;

// Создает новый объект-круг с указанием радиуса,

public function _construct($radius=100) {

$this->radius = $radius;

parent::_сonstruct();

}

// Отображает круг на экране.

public function show() {

list ($x, $y) = $this->getCoord();

$radius = $this->radius * $this->getScale();

echo "Рисуем круг: ($х, $у, $radius)<br>";

}

// Стирает фигуру с экрана,

public function hide() {

list ($x, $y) = $this->getCoord();

$radius = $this->radius * $this->getScale();

echo "Стираем круг: ($х, $у, $radius)<br>";

}

}

?>

1. Любой объект-круг является также и объектом-фигурой, а потому должен наследовать методы и свойства класса shape. Поэтому объявляем circle производным от Shape.

2. У круга, помимо свойств, присущих фигуре, есть и свои собственные данные: это его радиус. Создаем свойство $radius, в котором он будет храниться и объявляем его как private.

3. Круг имеет свой собственный конструктор, который вызывается в момент создания объекта. При создании указывается радиус круга. Фактически у каждого типа фигуры будут свои собственные конструкторы с различающимися списками параметров. Конструктор обычно не наследуется. НО мы обязательно должны вызвать конструктор базового класса shape, в противном случае фигура не будет проинициализирована( parent::_construct()).

В классе круг необходимо реализовать (переопределить) абстрактные функции show() и hide(). Они должны отображать круг на экране. Если в классе shape мы еще не имели информацию о том, как именно следует прорисовывать фигуру, то в классе circle это должно быть абсолютно ясно.

Виртуальный метод не обязательно должен быть абстрактным.

Абстрактные классы и методы

  1. Абстрактный метод нельзя вызвать, если он не был переопределен в производном классе. Собственно, написав функцию shape:: show() и поместив в нее вызов die(), мы как раз и гарантируем, что она обязательно будет переопределена в производном классе (иначе получим ошибку во время выполнения программы).

  2. Объект абстрактного класса невозможно создать.

  3. Любой класс, содержащий хотя бы один абстрактный метод, сам является абстрактным.

Абстрактные классы можно использовать только для одной цели: создавать от них производные. Сделаем из shape абстрактный класс, добавив ключевое слово abstract там, где это необходимо по логике.

<?php ## Абстрактный класс — геометрическая фигура,

abstract class Shape {

private $x=0, $y=0, $scale=1.0;

public function _construct() {

$this->show();

}

public function _destruct() {

$this->hide();

}

public final function moveBy($dx, $dy) {

$this->hide();

$this->x += $dx;

$this->y += $dy;

$this->show() ;

}

public final function resizeBy($coef) {

$this->hide();

$this->scale *= $coef;

$this->show() ;

}

public final function getCoord() { return array($this->x, $this->y); }

public final function getScale() { return $this->scale; }

// Абстрактные методы,

abstract protected function hide();

abstract protected function show();

}

?>

При объявлении абстрактного метода (например, show()) не нужно определять его тело — просто поставьте точку с запятой после его прототипа.

Совместимость родственных типов

Объекты производных классов допустимо использовать в том же контексте, что и объекты базовых, т.е. можно преобразовать circle в shape, но не наоборот.

Оператор instanceof

Проверка совместимости типов производится во время выполнения программы, а не во время ее трансляции. Для этого применяется новый оператор instanceof.

<?php ## Оператор instanceof.

$obj=new Circle(5);

if (!($obj instanceof Circle))

die("Argument must be an instance of Circle.<br>");

$obj->show();

?>

C помощью instanceof допустимо использовать также имя класса, заданное неявно (в переменной).

Задание.

  1. Расширить класс Message(из задания в Лекции №12), создав класс PrivateMessage. Переопределить метод show() класса Message так, чтобы для объектов класса PrivateMessage они отображались только у того пользователя, которому адресовалось сообщение.

  2. Сделать класс Message абстрактным и расширить его классами PrivateMessage и PublicMessage.

Множественное наследование и интерфейсы

До сих пор мы подразумевали, что у каждого производного класса может быть только единственный базовый. Наследовать свойства и методы сразу нескольких классов (например, писать class a extends в, с, d) в РНР нельзя.

Интерфейсы

Взамен множественного наследования пришел другой, упрощенный метод: использование интерфейсов. Интерфейс (interface) представляет собой обычный абстрактный класс, но только в нем не может быть свойств, и тела у всех методов не определены. Фактически некоторый интерфейс указывает лишь список методов, их аргументы и модификаторы доступа (обычно только protected и public). Допускается также описание констант внутри интерфейса с помощью ключевого слова const.

Класс, наследующий некоторый интерфейс обязан содержать в себе определения всех методов, объявленных в интерфейсе. Если хотя бы один из методов не будет реализован, вы не сможете создать объект класса: возникнет ошибка. Поэтому принято называть не класс, наследующий интерфейс, а класс, реализующий интерфейс.

Главное достоинство заключается в том, что класс может реализовывать сразу несколько интерфейсов. Для связи класса с интерфейсом используется ключевое слово implements:

interface Shape {

public function show(); // тело не указывается!

}

interface Movement {

public function move (); // вращает объект

//класс Circle реализует интерфейсы Shape и Movement

class Circle implements Shape, Movement {

public function show () { ... }

public function move () { ... }

}

Интерфейсы в свою очередь могут также наследовать (расширять) друг друга. При расширении интерфейсов нужно использовать ключевое слово extends, а не implements.

<?php ## Множественное наследование интерфейсов.

// Сущность: "материальный объект",

interface IWorldObject {

public function getCoord(); // возвращает координаты объекта

}

interface IWheeled {

public function getNumWheels(); // возвращает число колес

}

//интерфейс ITransport расширяет интерфейс IWorldObject

interface ITransport extends IWorldObject {

public function getNumPassengers(); // максимальное число пассажиров

}

//класс Audi реализует все три интерфейса, описанных выше

class Audi implements ITransport, IWheeled, IWorldObject {

private $coordArray;

public function getCoord() { return $coordArray; }

public function getNumWheels() { return 4; }

public function getNumPassengers() { return 5; }

}

?>

Интерфейс IWorldObject расширяется интерфейсом ITransport, который, в свою очередь, реализуется классом Audi. В то же время, Audi реализует IWorldObject и напрямую. Получается, что у Audi имеются две реализации интерфейса "материальный объект": непосредственный и через "транспортное средство". Такая ситуация довольно типична и является совершенно корректной: если некоторый интерфейс реализуется дважды, то в действительности в классе имеется лишь одна "ссылка" на него. Таким образом, никакого конфликта нет.

Интерфейсы и абстрактные классы

В случае если класс подключает к себе интерфейсы, но реализует не все методы в них, он автоматически становится абстрактным.

<?php ## Интерфейсы и абстрактные классы,

interface I {

public function F();

}

abstract class С implements I {

}

?>

Если мы пропустим ключевое слово abstract в описании класса, то получим уже знакомое нам сообщение: Fatal error: Class С contains 1 abstract methods and must therefore be declared abstract (I::F). Мы не можем создать в программе объект класса, в котором отсутствует один из методов, а такой класс как раз и называется абстрактным.

Задание.

Разработать несколько интерфейсов для работы с сообщениями на форуме. Реализовать разработанные интерфейсы несколькими способами и протестировать на задаче и Лекции№9.

Обработка ошибок и исключения

Термин "ошибка" имеет три различных значения.

1. Ошибочная ситуация — непосредственно факт наличия ошибки в программе. Это может быть, например, синтаксическая ошибка (скажем, пропущенная скобка), или же ошибка семантическая — смысловая (использование переменной, которая ранее не была определена).

2. Внутреннее сообщение об ошибке ("внутренняя ошибка"), которую выдает РНР в ответ на различные неверные действия программы (например, открытие несуществующего файла).

3. Пользовательское сообщение об ошибке ("пользовательская ошибка"), к которой причисляются все сообщения или состояния, генерируемые и обрабатываемые самой программой. Например, в скрипте авторизации ситуация "введен неверный пароль".

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

Для записи сообщений об ошибках в журнал в РНР существуют специальные средства: директивы log_errors, error_log, а также функция error_log(). Пользовательское сообщение об ошибке предназначено для отображения пользователю. При возникновении ошибочной ситуации такого рода пользователь должен увидеть осмысленный текст в браузере.

Виды ошибок

Информация об ошибке включает в себя текст диагностического сообщения, также уточняться и дополнительные данные, например, номер строки и имя файла, где возникла ошибочная ситуация. Если в программе возникла ошибочная ситуация, необходимо принять решение, что же в этом случае делать.

Все ошибки можно подразделить на два больших класса:

  • серьезные ошибки с невозможностью автоматического восстановления. Например, если вы пытаетесь открыть несуществующий файл;

  • "несерьезные" (нефатальные) ошибки, восстановление после которых не требуется, например, предупреждения (warnings), уведомления (notices). Обычно в случае возникновения такого рода ошибочных ситуаций нет необходимости предпринимать что-то особенное и нестандартное, вполне достаточно просто сохранить где-нибудь информацию об ошибке.

Несерьезные ошибки

Для обработки нефатальных ошибок, в РНР имеется инструмент, называемый перехватом ошибок. Метод заключается в том, что в программе пишется специальная функция — обработчик ошибки, которая вызывается РНР всякий раз, когда наступает та или иная ошибочная ситуация..

<?php ## Перехват ошибок и предупреждений.

// Определяем новую функцию-обработчик.

function myErrorHandler($errno, $msg, $file, $line) {

// Если используется @, ничего не делать.

if (error_reporting() == 0) return;

// Иначе — выводим сообщение.

echo '<div style="border-style:inset; border-width:2">';

echo "Произошла ошибка с кодом <b>$errno</b>!<br>";

echo "Файл: <tt>$file</tt>, строка $line.<br>";

echo "Текст ошибки: <i>$msg</i>";

echo "</div>";

}

// Регистрируем ее для всех типов ошибок.

set_error_handler("myErrorHandler", E_ALL);

// Вызываем функцию для несуществующего файла, чтобы

// сгенерировать предупреждение, которое будет перехвачено,

filemtime ("spoon") ;

?>

При нефатальных ошибках, программа всегда продолжает свою работу — просто в момент возникновения ошибочной ситуации вызывается функция-обработчик, а затем выполнение идет дальше.

Серьезные ошибки

Серьезные ошибки в общем случае невозможно обработать с использованием set_error_handler(), потому что в каждом конкретном случае необходимо писать "персональный" код восстановления.

В случае возникновения серьезной ошибки программа просто завершает работу по exit() или die(). Конечно, такой метод совершенно неприемлем в коде различных библиотек общего пользования: ведь вызывающая программа может не ожидать, что ее выполнение может вот так быть прервано из-за какой-нибудь мелочи вроде невозможности открытия файла журнала.

Практически все стандартные функции РНР в случае возникновения ошибочной ситуации возвращают false или null, а также вызывают trigger_error() для фиксирования диагностического сообщения. Например, функция fopen() при невозможности открытия файла возвращает false, и мы должны проверить результат на истинность.

Исключения

Исключения (exceptions) — это технология, позволяющая писать код восстановления после серьезной ошибки в удобном для программиста виде. С применением исключений перехват и обработка ошибок значительно упрощается.

Исключения также позволяют удобно передавать информацию о возникшей ошибке вниз по дереву (стеку) вызовов функций. Таким образом, код восстановления может находиться даже не в текущей процедуре, а в той, что ее вызывает.

Исключение — это некоторое сообщение об ошибке. При своей генерации оно автоматически передается в обработчик исключения. Любое исключение в программе представляет собой объект некоторого класса, создаваемый, как обычно, оператором new. Этот объект может содержать различную информацию, например, текст диагностического сообщения, а также номер строки и имя файла, в которых произошла генерация исключения. Допустимо добавлять и любые другие параметры.

Для работы с исключениями используют конструкции try...catch.

Код обработчика исключения помещается в блок инструкции catch(Exception $e). Аргумент блока catch определяет, в какую переменную должен быть записан перехваченный объект-исключение перед запуском кода обработчика. Также обязательно задается тип исключения — имя класса. Обработчик будет вызван только для тех объектов-исключений, которые совместимы с указанным типом (например, для объектов данного типа).

В блоке try размещается код, который может сгенерировать исключение. Любые исключения, сгенерированные внутри него (и только они), будут переданы соответствующему обработчику.

Инструкция throw используется для генерации исключения. Генерацию также называют возбуждением или даже выбрасыванием исключения. Инструкция throw не просто генерирует объект-исключение и передает его обработчику блока catch. Она также немедленно завершает работу текущего try-блока. Любое исключение представляет собой обычный объект РНР, который мы и создаем в операторе new.

<?php ## Простой пример использования исключений,

echo "Начало программы.<br>";

try {

// Код, в котором перехватываются исключения.

echo "Все, что имеет начало...<br>";

// Генерируем ("выбрасываем") исключение.

throw new Exception("Hello!");

echo "...имеет и конец.<br>";

} catch (Exception $e) {

// Код обработчика.

echo " Исключение: {$e->getMessage()}<br>";

}

echo "Конец программы.<br>";

?>

//результат работы сценария Начало программы.

Все, что имеет начало...

Исключение: Hello!

Конец программы.

Раскрутка стека

Инструкцию throw можно использовать не только непосредственно в try-блоке, но и внутри любой функции, которая оттуда вызывается. При этом производится выход не только из функции, содержащей throw, но также и из всех промежуточных процедур.

<?php ## Инструкция try во вложенных функциях,

echo "Начало программы.<br>";

try {

echo "Начало try-блока.<br>";

outer();

echo "Конец try-блока.<br>";

} catch (Exception $e) {

echo " Исключение: {$e->getMessage()}<br>";

}

echo "Конец программы.<br>";

function outer() {

echo "Вошли в функцию "._METHOD_ ."<br>";

inner();

echo "Вышли из функции ". _METHOD_ ."<br>";

}

function inner() {

echo "Вошли в функцию "._ METHOD_ ."<br>";

throw new Exception("Hello!")

echo "Вышли из функции ". _METHOD_ ."<br>";

}

?>

//Результат работы данного кода:

Начало программы.

Начало try-блока.

Вошли в функцию outer

Вошли в функцию inner

Исключение: Hello!

Конец программы.

Данное поведение инструкции throw называют раскруткой стека вызовов функции, потому что объект-исключение последовательно передается из одной функции в другую, каждый раз приводя к ее завершению — как бы "отматывает" стек.

Блоки-финализаторы

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

В языках программирования Java и Delphi для реализации кода-финализатора имеется очень удобная конструкция try...finally, призванная гарантировать выполнение некоторых действий в случае возникновения исключения или внезапного завершения функции по return. Однако РНР 5, пока не поддерживает конструкцию try...finally.

Перехват всех исключений

Поскольку любой класс-исключение произволен от класса Exception, мы можем написать один-единственный блок-обработчик для всех возможных исключений в программе:

echo "Начало программы.<br>";

try {

eatThis();

} catch (Exception $e) {

echo "Неперехваченное исключение: ". $e;

}

echo "Конец программы.<br>";

Таким образом, если в функции eatThis() возникнет любая исключительная ситуация, и объект-исключение не будет перехвачен внутри самой процедуры, сработает универсальный код восстановления .

Перехват всех исключений при помощи конструкции catch (Exception ...) позволяет нам обезопаситься от неожиданного завершения работы функции (или блока) и гарантировать выполнение некоторого кода в случае возникновения исключения. В этом отношении конструкция очень похожа на инструкцию finally, которой в РНР на данный момент нет.

Задание

  1. Создать свой класс Ошибки для описание исключительных ситуаций, которые могут возникнуть на форуме.

  2. Добавить обработку исключительных ситуаций, возникающих при работе форума. Например, попытка пользователя зайти на обсуждение темы, для которой он не зарегистрирован и т.д.

Работа с СУБД MySQL

База данных — совокупность связанных между собой данных, сохраняемая в двумерных таблицах информационной системы. Системой управления базами данных (СУБД) называется программное обеспечение информационной системы, обеспечивающей создание, ведение и совместное использование баз данных. В РНР есть ряд возможностей для работы с различными системами управления базами данных (например, SQLite, Sybase, Oracle и т. д.). Одной из них является MySQL.

База данных MySQL представляет собой организованный набор поименованных таблиц. Каждая таблица — неупорядоченный массив из однородных элементов, которые называются записями. Запись — неделимая единица информации в базе данных. Запись может содержать в себе одно или несколько именованных полей. Число и имена полей задаются при создании таблицы. Каждое поле имеет определенный тип (например, целое число, строка текста, массив символов и т. д.).

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

Архитектура MySQL

Одна из самых популярных СУБД, которые используются в Web-программировании, — MySQL. Она предназначена для создания сравнительно небольших баз данных и поддерживает некоторое подмножество языка запросов SQL.

SQL (Structured Query Language, язык структурированных запросов) — это специально разработанный стандарт языка запросов к базам данных. Основные команды:

  • создание/удаление таблицы;

  • создание новых записей в заданной таблице;

  • поиск и группировка записей, в том числе сразу в нескольких связанных между собой таблицах;

  • удаление записей, удовлетворяющих некоторому критерию;

  • обновление некоторых полей в указанных записях.

MySQL — это программа-сервер, постоянно работающая на компьютере. Клиентские программы (например, сценарии) посылают ей специальные запросы через механизм сокетов, она их обрабатывает и запоминает результат. Затем, также по специальному запросу клиента, весь этот результат или его часть передается обратно. Если размер результирующего набора данных слишком большой он передается частями. Механизм использования сокетов подразумевает технологию клиент-сервер, а это означает, что в системе должна быть запущена специальная программа — MySQL- сервер, которая принимает и обрабатывает запросы от программ.

Один сервер MySQL способен поддерживать сразу несколько баз данных, доступ к которым может разграничиваться именем пользователя (login) и паролем (password). Зная эти регистрационные сведения, можно работать с конкретной базой данных.

Администрирование базы данных

Для работы с СУБД необходимо установить какую-нибудь программу для администрирования MySQL. Их существует множество. Одна из самых популярных — MySQL-Front — работает в Windows и имеет привычный графический интерфейс. Ее можно скачать с сайта http://www.mysqlfront.de.

Для работы с базой данных прямо в окне браузера существует система phpMyAdmin, целиком написанная на РНР и устанавливаемая прямо в каталог документов сервера хостинг-провайдера. Ее можно найти по адресу http://phpmyadmin.net. Система phpMyAdmin можно установить вместе с WEB-сервером, например denwer. Запустить ее можно введя в браузере строку http://localhost/tools/phpMyAdmin.

С помощью систем администрирования вы можете просматривать и редактировать свои базы данных и расположенные в них таблицы. Вы даже можете изменять структуру таблиц (например, добавлять в них новые поля), а также просматривать разного рода статистику. Кроме того, они позволяют в удобном виде просматривать результаты запросов, введенных вручную — это особенно полезно при отладке скриптов, когда непонятно, почему та или иная команда SQL работает не так, как ожидается.

Алгоритм работы с базой данных

Вначале надо подключиться к серверу СУБД, затем — переслать ему одну или несколько команд, обрабатывая возможные ошибки. В конце можно закрыть соединение с сервером.

Соединение с сервером

Прежде чем работать с базой данных, необходимо установить с ней сетевое соединение, а также провести авторизацию пользователя. Для этого служит функция mysql_connect().

int mysql_connect ([ string $host] [,string $user] [, string $passvrord])

Функция mysql_connect () устанавливает сетевое соединение с базой данных MySQL, расположенной на хосте $host (по умолчанию это localhost, т. е. текущий компьютер), и возвращает идентификатор открытого соединения. Вся дальнейшая работа ведется именно с этим идентификатором. При регистрации указывается имя пользователя $user и пароль $password (по умолчанию имя пользователя, от которого запущен текущий процесс, и пустой пароль). Строка $host также может включать в себя номер порта в формате: имя_хоста: порт (если сервер MySQL настроен не на стандартный, а на какой-то другой порт). Соединение с MySQL-сервером будет автоматически закрыто по завершении работы сценария, либо же при вызове функции mysql_ciose(). Если вы планируете открывать всего одно соединение с базой данных за время работы сценария, то можете не сохранять возвращенное значение, а также не указывать идентификатор соединения при вызове всех остальных функций.

До того как послать первый запрос серверу MySQL, необходимо указать, с какой базой данных мы собираемся работать. Для этого и предназначена функция.

int mysql_select_db (string $dbname [,int $link_identifier])

Она уведомляет РНР, что в дальнейших операциях с соединением $link_identifier (или с последним открытым соединением, если указанный параметр не задан) будет использоваться база данных $dbname. Один и тот же пользователь может иметь доступ сразу к нескольким базам данных.

Обработка ошибок

Если в процессе работы с MySQL возникают ошибки (например, в запросе не сбалансированы скобки или же не хватает параметров), то сообщение об ошибке и ее номер можно получить с помощью двух функций.

int mysql_errno ([int $link_identifier])

Функция возвращает номер последней зарегистрированной ошибки. Идентификатор соединения $link_identifier можно не указывать, если за время работы сценария было установлено только одно соединение.

string mysql_error( [int $link_identifier])

Эта функция возвращает не номер, а строку, содержащую текст сообщения об ошибке. Ее удобно применять в отладочных целях. Обычно mysql_error() используют вместе с конструкцией or die(), например:

@mysql_connect("localhost", "user", "password")

or die("Error connecting to database: ".mysql_error());

Оператор @ служит для подавления стандартного предупреждения, которое может возникнуть в случае ошибки.

Получение списка полей таблицы

Для получения списка полей таблицы используют команду - mysql_list_fields.

resource mysql_list_fields (string database_name, string table_name [,resource link_identifier])

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

Функция mysql_field_name возвращает имя поля, полученного в результате выполнения запроса. Функция mysql_field_len возвращает длину поля. Функция mysql_field_type возвращает тип поля, а функция mysql_field_flags возвращает список флагов поля, записанных через пробел. Типы поля могут быть int, real, string, blob и т.д. Флаги могут быть not_null, primary_key, unique_key, blob, auto_increment и т.д.

Синтаксис у всех этих команд одинаков:

string mysql_field_name (resource result, int field_offset)

string mysql_field_type (resource result, int field_offset)

string mysql_field_flags (resource result, int field_offset)

string mysql_field_len (resource result, int field_offset)

Здесь result - это идентификатор результата запроса (например, запроса, отправленного функциями mysql_list_fields), а field_offset - порядковый номер поля в результате.

Функция mysql_list_fields возвращает указатель на таблицу. Чтобы получить из этой таблицы конкретные значения, нужно задействовать специальные функции, которые построчно читают эту таблицу. К таким функциям и относятся mysql_field_name и т.п. Чтобы перебрать все строки в таблице результата выполнения запроса, нужно знать число строк в этой таблице. Команда mysql_num_rows(ресурс result) возвращает число строк во множестве результатов result.

<?

$conn = mysql_connect("localhost","","")

or die("Невозможно установить соединение: ". mysql_error());

echo "Соединение установлено";

//выбов базы данных book

mysql_select_db("book");

//получение списка полей таблицы Artifacts

$list_f = mysql_list_fields ( "book","Artifacts",$conn);

//получение количества полей таблицы Artifacts

$n = mysql_num_fields($list_f);

//определение для каждого поля его тип, имя, длину и флаги

for($i=0;$i<$n; $i++){

$type = mysql_field_type($list_f, $i);

$name_f = mysql_field_name($list_f,$i);

$len = mysql_field_len($list_f, $i);

$flags_str = mysql_field_flags ( $list_f, $i);

echo "<br>Имя поля: ". $name_f;

echo "<br>Тип поля: ". $type;

echo "<br>Длина поля: ". $len;

echo "<br>Строка флагов поля: ". $flags_str . "<hr>";

}

?>

Если в таблице есть два поля, то в результате может получиться следущее:

Имя поля: id

Тип поля: int

Длина поля: 11

Строка флагов поля: not_null primary_key auto_increment

Имя поля: title

Тип поля: string

Длина поля: 255

Строка флагов поля:

Задание.

  1. Создать форму для отображения любой таблицы базы данных. Форма должна содержать список всех таблиц некоторой базы данных. При выборе какой-то таблицы из списка, в форме выводятся соответствующие поля для заполнения таблицы. Например: если таблица содержала поля id – int ,title – varchar(50), present – bool, где id – счетчик, то в окне должна появится форма с двумя полями – текстовым полем для ввода title, размером 50, и флажок для поля present.

  2. Создать базу данных для форума. Разработать набор таблиц для хранения информации о пользователях форума и обмене сообщений между ними.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]