Статические методы и свойства

До текущего времени мы рассматривали классы как шаблоны для объектов. А сами объекты как динамические компоненты. Однако все не так просто.

Мы можем получить доступ к методам и свойствам в контексте класса, не создавая объектов. Такие свойства и методы называются статическими и добавляются с помощью ключа static.

Рассмотрим пример: в Java есть класс Math, который содержит множество математических функций. Все методы в данном классе — статическими. Это значит, что не нужно создавать объект данного класса для расчетов. Рассмотрим код эмулирующим данный функционал:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
	<?php
class Math {
  private static $count = 0;
  public function __construct() {
    self::$count++;
  }
  public static function calcSin($x) {
    return sin($x);
  }
  public static function calcSQRT($x) {
    return sqrt($x);
  }
  public static function getCount() {
    return self::$count;
  }
}
echo Math::calcSin(1);
echo "<br />";
echo Math::calcSQRT(9);
echo "<br />";
$math = new Math();
$math_2 = new Math();
echo Math::getCount();
?>

Обратите внимание на способ обращения к статическим свойствам с использованием имени класса. Для обращения используется синтаксис «::».

Также, внутри кода класса к статическим свойствам и методам, используем ключевое слово self. Напомним, что псевдопеременная this используется для обращения к текущему объекту.

Рассмотрим пример:

1
2
3
4
5
6
7
8
9
10
11
class StaticExample
{
	static public $num = 0;
 
	static public function HelloWorld()
	{
		// Доступ к статическому свойству внутри класса
		self::$num++;
		echo 'Hello, world!';
	}
}

Выполните

Задание 1.Создайте класс описанный в примере выше. Вызовите его метод HelloWorld() обращаясь напрямую к классу. Затем выведите его свойство num.

Постоянные свойства

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

В php 5 можно определить константу внутри класса. Для этого используется ключевое слово const. Знак доллара не ставится. По соглашению их имена пишутся с большой буквы.

1
2
3
4
5
	class SomeClass
{
	const AVAILABLE = 0;
	const COUNT = 10;
}

Выполнить

Задание 2. Создайте класс, который содержит константу равную G=9.8 и константу PI=3.1415926. И два метода — первый на основе массы m рассчитывает вес тела (m*G), а второй на основе радиуса — площадь круга (PI*R*R).

Продемонстрируйте работу объекта на основе созданного класса.


Задание 3. Присвойте константе новое значение. Изучите вывод об ошибке.

Задание 4. Создайте класс1 содержащий константы a=5, b=7, d=4. Создайте класс2, который входящее число возводит в квадрат. На основе класса2 создайте объект. В качестве параметра передайте объекту константы из класса1. Результат продемонстрируйте.

Абстрактные классы PHP

Самое главное, что необходимо понять так это то, что нельзя создать объекты на основе абстрактных классов. Также существует такое понятие как абстрактные методы. Абстрактные методы — это методы, реализации которых ещё не существует. Абстрактные методы должны быть обязательно реализованы в классах-наследниках.

Для того, чтобы закрепить полученные знания, давайте перепишем задачу из прошлой статьи, но с использованием абстрактного класса. Начнём с класса «Car», представляющего «абстрактный автомобиль» (файл «car.php»):

1
2
3
4
5
6
7
8
9
10
11
12
<?php
  abstract class Car {
    public $x;
    public $y;
    public function __construct($x, $y) {
      $this->x = $x;
      $this->y = $y;
    }
    abstract public function move ($x, $y);
    abstract public function sound();
  }
?>

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

Теперь посмотрите, какой вид имеет класс «Легковой автомобиль», который, в нашем случае, является уже не абстрактностью, а конкретной моделью (файл «auto.php»):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
  require_once "car.php";
  class Auto extends Car {
    public function move($x, $y) {
      $this->sound();
      echo "Движение легкового автомобиля из координат ($this->x, $this->y) в координаты ($x, $y)<br />";
      $this->x = $x;
      $this->y = $y;
    }
    public function sound() {
      echo "Звук движения легкового автомобиля<br />";
    }
  }
?>

В данном примере мы реализовали два абстрактных метода, пришедших из класса «Car», родителя для класса «Auto».

Рассмотрим объект «Auto»:

1
2
3
4
5
6
7
8
  require_once "auto.php";
  $auto = new Auto(10, 20);
  echo $auto->x;
  echo "<br />";
  echo $auto->y;
  echo "<br />";
  $auto->move(5, 15);
?>

Как видите, мы создали объект «Auto», вывели его свойства, воспользовались методом движения.

Понятие о интерфейсах

Интерфейс — это набор методов без реализации. То есть в интерфейс входят методы с именем и входными параметрами. Больше ничего нет. Любой класс, который реализует (обратите внимание, что не наследует, а реализует) данный интерфейс, обязан реализовать каждый метод. Чтобы стало ещё понятнее, хочется привести аналог из жизни. Каждый человек выполняет определённые функции. Например, учится, работает, убирает квартиру, готовит еду и занимается другими очевидными вещами. Можете считать, что интерфейс — это область занятий, например, учёба, работа, уборка квартиры, готовка еды. А методы интерфейса — это уже конкретная задача в данной области. Например, в уборке квартиры могут быть такие методы: мойка посуды, мойка пола, вынос мусора и другие. В готовке еды могут быть такие методы: готовка борща, готовка мяса, чистка картошки и прочее. Надеюсь, мысль Вы уловили.

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

Давайте разберём простой пример, создав следующий интерфейс (в файле «fileinterface.php»):

1
2
3
4
5
6
<?php
  interface FileInterface {
    public function readFromFile($path);
    public function writeToFile($path, $some);
  }
?>

То есть данный интерфейс просто описывает работу с файлом. Соответственно, те объекты, которые должны читать из файла и записывать различные данные, обязаны реализовать интерфейс «FileInterface».

Создадим ещё один интерфейс (в файле «client.php»):

1
2
3
4
5
6
<?php
  interface Client {
    public function buy ($id);
    public function repayment($id);
  }
?>

Данный интерфейс реализует функцию клиента, то есть можно что-то купить (задаётся $id), а также что-то возвратить обратно (тоже задаётся по $id).

И, наконец, класс, который реализует эти интерфейсы, то есть класс у которого области задач две — быть клиентом и работать с файлом (файл «shop.php»):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
  require_once "fileinterface.php";
  require_once "client.php";
  class Shop implements FileInterface, Client{
    public function readFromFile($path) {
      echo "Считываем из файла и возвращаем строку<br />";
    }
    public function writeToFile($path, $some) {
      echo "Записываем в файл данные $some<br />";
    }
    public function buy($id) {
      echo "Спасибо за покупку<br />";
      $this->writeToFile("data.db", "Был куплен товар $id");
    }
    public function repayment($id) {
      $this->readFromFile("data.db");
      //Тут, допустим, проверка того, была ли на самом деле покупка товара $id
      $this->writeToFile("data.db", "Был сделан возврат товара $id");
    }
  }
?>

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

И, наконец, простой пример, который использует класс Shop:

1
2
3
4
5
6
<?php
  require_once "shop.php";
  $shop = new Shop();
  $shop->buy(5);
  $shop->repayment(5);
?>

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

Домашнее задание

Выполнить: задание 2, 3, 4 на текущей странице.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *