Статьи

Объектно-ориентированный PHP для начинающих

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

Чтобы увидеть, что вы можете делать с объектно-ориентированным PHP, взгляните на огромный спектр PHP-скриптов на CodeCanyon, например, на эту объектно-ориентированную среду SQLite .

Или, если вы боретесь с подходом «сделай сам», вы можете нанять профессионала в Envato Studio либо для исправления ошибок , либо для создания полнофункциональных PHP-приложений и модулей .

Объектно-ориентированное программирование — это стиль кодирования, который позволяет разработчикам группировать похожие задачи в классы . Это помогает сохранить код, следуя принципу «не повторяйся» (СУХОЙ), и прост в обслуживании.

«Объектно-ориентированное программирование — это стиль кодирования, который позволяет разработчикам группировать похожие задачи в классы ».

Одним из основных преимуществ DRY-программирования является то, что, если в вашей программе изменяется часть информации, обычно для обновления кода требуется только одно изменение. Один из самых больших кошмаров для разработчиков — поддержка кода, в котором данные объявляются снова и снова, а это означает, что любые изменения в программе становятся бесконечно более разочаровывающей игрой Where’s Waldo? как они охотятся за дублированными данными и функциональностью.

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

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

Фотографии Мгновенного Джефферсона и Джона Уорделла

Разработчики начинают говорить об объектах и ​​классах, и они кажутся взаимозаменяемыми терминами. Это не тот случай, однако.

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

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

Таким образом, объект похож на настоящий дом, построенный в соответствии с этим планом. Данные, хранящиеся в объекте, похожи на дерево, провода и бетон, составляющие дом: без сборки в соответствии с планом, это просто куча вещей. Однако, когда все это объединяется, это становится организованным, полезным домом.

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

Синтаксис создания класса довольно прост: объявите класс с помощью ключевого слова class , за которым следует имя класса и набор фигурных скобок ( {} ):

1
2
3
4
5
6
7
8
<?php
 
class MyClass
{
  // Class properties and methods go here
}
 
?>

После создания класса можно создать новый класс и сохранить его в переменной с помощью ключевого слова new :

1
$obj = new MyClass;

Чтобы увидеть содержимое класса, используйте var_dump() :

1
var_dump($obj);

Попробуйте этот процесс, поместив весь предыдущий код в новый файл с именем test.php в папке [your local]:

01
02
03
04
05
06
07
08
09
10
11
12
<?php
 
class MyClass
{
    // Class properties and methods go here
}
 
$obj = new MyClass;
 
var_dump($obj);
 
?>

Загрузите страницу в браузере по адресу http://localhost/test.php и должно отобразиться следующее:

1
object(MyClass)#1 (0) { }

В простейшей форме вы только что завершили свой первый сценарий ООП.

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

Чтобы добавить свойство в MyClass , добавьте следующий код в ваш скрипт:

01
02
03
04
05
06
07
08
09
10
11
12
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
}
 
$obj = new MyClass;
 
var_dump($obj);
 
?>

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

Чтобы прочитать это свойство и вывести его в браузер, укажите объект для чтения и свойство для чтения:

1
echo $obj->prop1;

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

Измените скрипт в test.php чтобы прочитать свойство, а не выводить весь класс, изменив код, как показано ниже:

01
02
03
04
05
06
07
08
09
10
11
12
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
}
 
$obj = new MyClass;
 
echo $obj->prop1;
 
?>

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

1
I’m a class property!

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

Например, чтобы создать методы, которые бы устанавливали и получали значение свойства класса $prop1 , добавьте в свой код следующее:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
$obj = new MyClass;
 
echo $obj->prop1;
 
?>

Примечание. ООП позволяет объектам ссылаться на себя, используя $this . При работе внутри метода используйте $this же, как вы используете имя объекта вне класса.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
$obj = new MyClass;
 
echo $obj->getProperty();
 
$obj->setProperty(«I’m a new property value!»);
 
echo $obj->getProperty();
 
?>

Перезагрузите браузер, и вы увидите следующее:

1
2
I’m a class property!
I’m a new property value!

«Сила ООП становится очевидной при использовании нескольких экземпляров
тот же класс.»

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
// Create two objects
$obj = new MyClass;
$obj2 = new MyClass;
 
// Get the value of $prop1 from both objects
echo $obj->getProperty();
echo $obj2->getProperty();
 
// Set new values for both objects
$obj->setProperty(«I’m a new property value!»);
$obj2->setProperty(«I belong to the second instance!»);
 
// Output both objects’ $prop1 value
echo $obj->getProperty();
echo $obj2->getProperty();
 
?>

Когда вы загружаете результаты в ваш браузер, они выглядят следующим образом:

1
2
3
4
I’m a class property!
I’m a class property!
I’m a new property value!
I belong to the second instance!

Как видите, ООП хранит объекты как отдельные объекты , что облегчает разделение различных частей кода на небольшие связанные пакеты.

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

Когда объект создается, часто желательно установить несколько вещей сразу. Чтобы справиться с этим, PHP предоставляет магический метод __construct() , который вызывается автоматически всякий раз, когда новый объект
создано.

Чтобы проиллюстрировать концепцию конструкторов, добавьте в MyClass конструктор, который будет выводить сообщение всякий раз, когда создается новый экземпляр класса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
// Create a new object
$obj = new MyClass;
 
// Get the value of $prop1
echo $obj->getProperty();
 
// Output a message at the end of the file
echo «End of file.<br />»;
 
?>

Примечание__CLASS__ возвращает имя класса, в котором он вызывается; это то, что известно как магическая константа . Есть несколько доступных магических констант, о которых вы можете прочитать подробнее в руководстве по PHP.

Перезагрузка файла в вашем браузере даст следующий результат:

1
2
3
The class «MyClass» was initiated!
I’m a class property!
End of file.

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

Вывести сообщение, когда объект уничтожен, определив магический метод
__destruct() в MyClass :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
// Create a new object
$obj = new MyClass;
 
// Get the value of $prop1
echo $obj->getProperty();
 
// Output a message at the end of the file
echo «End of file.<br />»;
 
?>

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

1
2
3
4
The class «MyClass» was initiated!
I’m a class property!
End of file.
The class «MyClass» was destroyed.

«Когда достигнут конец файла, PHP автоматически освобождает все ресурсы».

Чтобы явно вызвать деструктор, вы можете уничтожить объект, используя
функция unset() :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
// Create a new object
$obj = new MyClass;
 
// Get the value of $prop1
echo $obj->getProperty();
 
// Destroy the object
unset($obj);
 
// Output a message at the end of the file
echo «End of file.<br />»;
 
?>

Теперь результат изменяется на следующий, когда загружается в ваш браузер:

1
2
3
4
The class «MyClass» was initiated!
I’m a class property!
The class «MyClass» was destroyed.
End of file.

Чтобы избежать ошибки, если скрипт пытается вывести MyClass в виде строки, используется другой магический метод, называемый __toString() .

Без __toString() попытка вывести объект в виде строки приводит к фатальной ошибке . Попытайтесь использовать echo для вывода объекта без использования магического метода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
// Create a new object
$obj = new MyClass;
 
// Output the object as a string
echo $obj;
 
// Destroy the object
unset($obj);
 
// Output a message at the end of the file
echo «End of file.<br />»;
 
?>

Это приводит к следующему:

1
2
3
The class «MyClass» was initiated!
 
Catchable fatal error: Object of class MyClass could not be converted to string in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 40

Чтобы избежать этой ошибки, добавьте __toString() :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function __toString()
  {
      echo «Using the toString method: «;
      return $this->getProperty();
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
// Create a new object
$obj = new MyClass;
 
// Output the object as a string
echo $obj;
 
// Destroy the object
unset($obj);
 
// Output a message at the end of the file
echo «End of file.<br />»;
 
?>

В этом случае попытка преобразовать объект в строку приводит к вызову метода getProperty() . Загрузите тестовый скрипт в ваш браузер, чтобы увидеть результат:

1
2
3
4
The class «MyClass» was initiated!
Using the toString method: I’m a class property!
The class «MyClass» was destroyed.
End of file.

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function __toString()
  {
      echo «Using the toString method: «;
      return $this->getProperty();
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
class MyOtherClass extends MyClass
{
  public function newMethod()
  {
      echo «From a new method in » .
  }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Output the object as a string
echo $newobj->newMethod();
 
// Use a method from the parent class
echo $newobj->getProperty();
 
?>

После перезагрузки тестового файла в вашем браузере выводится следующее:

1
2
3
4
The class «MyClass» was initiated!
From a new method in MyOtherClass.
I’m a class property!
The class «MyClass» was destroyed.

Чтобы изменить поведение существующего свойства или метода в новом классе, вы можете просто перезаписать его, объявив его снова в новом классе:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function __toString()
  {
      echo «Using the toString method: «;
      return $this->getProperty();
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
class MyOtherClass extends MyClass
{
  public function __construct()
  {
      echo «A new constructor in » .
  }
 
  public function newMethod()
  {
      echo «From a new method in » .
  }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Output the object as a string
echo $newobj->newMethod();
 
// Use a method from the parent class
echo $newobj->getProperty();
 
?>

Это изменяет вывод в браузере на:

1
2
3
4
A new constructor in MyOtherClass.
From a new method in MyOtherClass.
I’m a class property!
The class «MyClass» was destroyed.

Чтобы добавить новую функциональность в унаследованный метод, оставив исходный метод без изменений, используйте ключевое слово parent с оператором разрешения области действия ( :: :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function __toString()
  {
      echo «Using the toString method: «;
      return $this->getProperty();
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  public function getProperty()
  {
      return $this->prop1 .
  }
}
 
class MyOtherClass extends MyClass
{
  public function __construct()
  {
      parent::__construct();
      echo «A new constructor in » .
  }
 
  public function newMethod()
  {
      echo «From a new method in » .
  }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Output the object as a string
echo $newobj->newMethod();
 
// Use a method from the parent class
echo $newobj->getProperty();
 
?>

Это выводит результат как родительского конструктора, так и конструктора нового класса:

1
2
3
4
5
The class «MyClass» was initiated!
A new constructor in MyOtherClass.
From a new method in MyOtherClass.
I’m a class property!
The class «MyClass» was destroyed.

Для дополнительного контроля над объектами, методам и свойствам назначается видимость. Это определяет, как и откуда можно получить доступ к свойствам и методам. Существует три ключевых слова видимости: public , protected и private . В дополнение к видимости, метод или свойство могут быть объявлены как static , что позволяет получить к ним доступ без создания экземпляра класса.

«Для дополнительного контроля над объектами методам и свойствам назначается видимость».

Примечание. Видимость — это новая функция, появившаяся в PHP 5. Информацию о совместимости ООП с PHP 4 см. На странице руководства PHP.

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

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

Объявите метод getProperty() как защищенный в MyClass и попытайтесь получить к нему доступ непосредственно из класса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function __toString()
  {
      echo «Using the toString method: «;
      return $this->getProperty();
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  protected function getProperty()
  {
      return $this->prop1 .
  }
}
 
class MyOtherClass extends MyClass
{
  public function __construct()
  {
      parent::__construct();
echo «A new constructor in » .
  }
 
  public function newMethod()
  {
      echo «From a new method in » .
  }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Attempt to call a protected method
echo $newobj->getProperty();
 
?>

При попытке запустить этот скрипт появляется следующая ошибка:

1
2
3
4
The class «MyClass» was initiated!
A new constructor in MyOtherClass.
 
Fatal error: Call to protected method MyClass::getProperty() from context » in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 55

Теперь создайте новый метод в MyOtherClass для вызова метода getProperty() :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function __toString()
  {
      echo «Using the toString method: «;
      return $this->getProperty();
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  protected function getProperty()
  {
      return $this->prop1 .
  }
}
 
class MyOtherClass extends MyClass
{
  public function __construct()
  {
      parent::__construct();
echo «A new constructor in » .
  }
 
  public function newMethod()
  {
      echo «From a new method in » .
  }
 
  public function callProtected()
  {
      return $this->getProperty();
  }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Call the protected method from within a public method
echo $newobj->callProtected();
 
?>

Это генерирует желаемый результат:

1
2
3
4
The class «MyClass» was initiated!
A new constructor in MyOtherClass.
I’m a class property!
The class «MyClass» was destroyed.

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

Чтобы продемонстрировать это, объявите getProperty() как закрытое в MyClass и callProtected() вызвать callProtected() из
MyOtherClass :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function __toString()
  {
      echo «Using the toString method: «;
      return $this->getProperty();
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  private function getProperty()
  {
      return $this->prop1 .
  }
}
 
class MyOtherClass extends MyClass
{
  public function __construct()
  {
      parent::__construct();
      echo «A new constructor in » .
  }
 
  public function newMethod()
  {
      echo «From a new method in » .
  }
 
  public function callProtected()
  {
      return $this->getProperty();
  }
}
 
// Create a new object
$newobj = new MyOtherClass;
 
// Use a method from the parent class
echo $newobj->callProtected();
 
?>

Перезагрузите браузер, и появится следующая ошибка:

1
2
3
4
The class «MyClass» was initiated!
A new constructor in MyOtherClass.
 
Fatal error: Call to private method MyClass::getProperty() from context ‘MyOtherClass’ in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 49

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

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

Чтобы продемонстрировать это, добавьте статическое свойство с именем $count и статический метод с именем plusOne() в MyClass . Затем установите цикл do...while while для вывода увеличенного значения $count если значение меньше 10:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php
 
class MyClass
{
  public $prop1 = «I’m a class property!»;
 
  public static $count = 0;
 
  public function __construct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was initiated!<br />’;
  }
 
  public function __destruct()
  {
      echo ‘The class «‘, __CLASS__, ‘» was destroyed.<br />’;
  }
 
  public function __toString()
  {
      echo «Using the toString method: «;
      return $this->getProperty();
  }
 
  public function setProperty($newval)
  {
      $this->prop1 = $newval;
  }
 
  private function getProperty()
  {
      return $this->prop1 .
  }
 
  public static function plusOne()
  {
      return «The count is » .
  }
}
 
class MyOtherClass extends MyClass
{
  public function __construct()
  {
      parent::__construct();
      echo «A new constructor in » .
  }
 
  public function newMethod()
  {
      echo «From a new method in » .
  }
 
  public function callProtected()
  {
      return $this->getProperty();
  }
}
 
do
{
  // Call plusOne without instantiating MyClass
  echo MyClass::plusOne();
} while ( MyClass::$count < 10 );
 
?>

Примечание. При доступе к статическим свойствам знак доллара
( $ ) следует после оператора разрешения области.

Когда вы загружаете этот скрипт в ваш браузер, выводится следующее:

01
02
03
04
05
06
07
08
09
10
The count is 1.
The count is 2.
The count is 3.
The count is 4.
The count is 5.
The count is 6.
The count is 7.
The count is 8.
The count is 9.
The count is 10.

«Стиль комментирования DocBlock широко распространен
принят метод документирования занятий «.

Хотя он и не является официальной частью ООП, стиль комментирования DocBlock является широко распространенным методом документирования классов. Помимо предоставления стандарта для
разработчикам, чтобы использовать при написании кода, он также был принят многими наиболее популярными наборами разработки программного обеспечения (SDK), такими как Eclipse и NetBeans , и будет использоваться для генерации подсказок кода.

DocBlock определяется с помощью комментария блока, который начинается с дополнительной звездочки:

1
2
3
/**
* This is a very basic DocBlock
*/

Настоящая сила DocBlocks заключается в возможности использовать теги , которые начинаются с символа at ( @ ), за которым сразу следует имя тега и значение тега. Теги DocBlock позволяют разработчикам определять авторов файла, лицензию для класса, информацию о свойстве или методе и другую полезную информацию.

Наиболее распространенные теги:

  • @author : автор текущего элемента (который может быть классом, файлом, методом или любым другим фрагментом кода) указан в списке с помощью этого тега. Несколько тегов авторов могут использоваться в одном и том же DocBlock, если зачислено более одного автора. Формат имени автора — John Doe <john.doe@email.com> .
  • @copyright : это означает год авторского права и имя владельца авторских прав для текущего элемента. Формат — 2010 Copyright Holder .
  • @license : это ссылка на лицензию для текущего элемента. Формат информации о лицензии
    http://www.example.com/path/to/license.txt License Name .
  • @var : содержит тип и описание переменной или свойства класса. Формат — type element description .
  • @param : этот тег показывает тип и описание параметра функции или метода. Формат — это type $element_name element description .
  • @return : тип и описание возвращаемого значения функции или метода представлены в этом теге. Формат — это type return element description .

Пример класса, прокомментированный с DocBlocks, может выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
 
/**
 * A simple class
 *
 * This is the long description for this class,
 * which can span as many lines as needed.
 * not required, whereas the short description is
 * necessary.
 *
 * It can also span multiple paragraphs if the
 * description merits that much verbiage.
 *
 * @author Jason Lengstorf <jason.lengstorf@ennuidesign.com>
 * @copyright 2010 Ennui Design
 * @license http://www.php.net/license/3_01.txt PHP License 3.01
 */
class SimpleClass
{
  /**
   * A public variable
   *
   * @var string stores data for the class
   */
  public $foo;
 
  /**
   * Sets $foo to a new value upon class instantiation
   *
   * @param string $val a value required for the class
   * @return void
   */
  public function __construct($val)
  {
      $this->foo = $val;
  }
 
  /**
   * Multiplies two integers
   *
   * Accepts a pair of integers and returns the
   * product of the two.
   *
   * @param int $bat a number to be multiplied
   * @param int $baz a number to be multiplied
   * @return int the product of the two parameters
   */
  public function bar($bat, $baz)
  {
      return $bat * $baz;
  }
}
 
?>

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

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

«Хотя это может показаться пугающим на первый взгляд, ООП на самом деле предоставляет более простой подход к работе с данными»

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

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

Вот процедурный подход к нашему примеру:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
 
function changeJob($person, $newjob)
{
  $person[‘job’] = $newjob;
  return $person;
}
 
function happyBirthday($person)
{
  ++$person[‘age’];
  return $person;
}
 
$person1 = array(
  ‘name’ => ‘Tom’,
  ‘job’ => ‘Button-Pusher’,
  ‘age’ => 34
);
 
$person2 = array(
  ‘name’ => ‘John’,
  ‘job’ => ‘Lever-Puller’,
  ‘age’ => 41
);
 
// Output the starting values for the people
echo «<pre>Person 1: «, print_r($person1, TRUE), «</pre>»;
echo «<pre>Person 2: «, print_r($person2, TRUE), «</pre>»;
 
// Tom got a promotion and had a birthday
$person1 = changeJob($person1, ‘Box-Mover’);
$person1 = happyBirthday($person1);
 
// John just had a birthday
$person2 = happyBirthday($person2);
 
// Output the new values for the people
echo «<pre>Person 1: «, print_r($person1, TRUE), «</pre>»;
echo «<pre>Person 2: «, print_r($person2, TRUE), «</pre>»;
 
?>

При выполнении код выдает следующее:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Person 1: Array
(
  [name] => Tom
  [job] => Button-Pusher
  [age] => 34
)
Person 2: Array
(
  [name] => John
  [job] => Lever-Puller
  [age] => 41
)
Person 1: Array
(
  [name] => Tom
  [job] => Box-Mover
  [age] => 35
)
Person 2: Array
(
  [name] => John
  [job] => Lever-Puller
  [age] => 42
)

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

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

Это где ООП вмешивается и помогает вам очистить вещи.

Вот подход ООП к нашему примеру:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php
 
class Person
{
  private $_name;
  private $_job;
  private $_age;
 
  public function __construct($name, $job, $age)
  {
      $this->_name = $name;
      $this->_job = $job;
      $this->_age = $age;
  }
 
  public function changeJob($newjob)
  {
      $this->_job = $newjob;
  }
 
  public function happyBirthday()
  {
      ++$this->_age;
  }
}
 
// Create two new people
$person1 = new Person(«Tom», «Button-Pusher», 34);
$person2 = new Person(«John», «Lever Puller», 41);
 
// Output their starting point
echo «<pre>Person 1: «, print_r($person1, TRUE), «</pre>»;
echo «<pre>Person 2: «, print_r($person2, TRUE), «</pre>»;
 
// Give Tom a promotion and a birthday
$person1->changeJob(«Box-Mover»);
$person1->happyBirthday();
 
// John just gets a year older
$person2->happyBirthday();
 
// Output the ending values
echo «<pre>Person 1: «, print_r($person1, TRUE), «</pre>»;
echo «<pre>Person 2: «, print_r($person2, TRUE), «</pre>»;
 
?>

Это выводит следующее в браузере:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Person 1: Person Object
(
  [_name:private] => Tom
  [_job:private] => Button-Pusher
  [_age:private] => 34
)
 
Person 2: Person Object
(
  [_name:private] => John
  [_job:private] => Lever Puller
  [_age:private] => 41
)
 
Person 1: Person Object
(
  [_name:private] => Tom
  [_job:private] => Box-Mover
  [_age:private] => 35
)
 
Person 2: Person Object
(
  [_name:private] => John
  [_job:private] => Lever Puller
  [_age:private] => 42
)

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

«ООП значительно снизит вашу рабочую нагрузку, если все будет реализовано правильно».

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

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

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

Предположим, у вас есть приложение с 150 классами, которые вызываются динамически через файл контроллера в корне файловой системы вашего приложения. Все 150 классов соответствуют соглашению об именах class.classname.inc.php и находятся в папке inc вашего приложения.

Контроллер может реализовать __autoload() PHP __autoload() чтобы динамически извлекать только те классы, которые ему нужны по мере их __autoload() , вместо включения всех 150 в файл контроллера на всякий случай или придумать какой-нибудь умный способ включения файлов в ваш собственный код :

1
2
3
4
5
6
<?php
  function __autoload($class_name)
  {
      include_once ‘inc/class.’
  }
?>

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

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

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

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

Многие преимущества, описанные в этом разделе, являются продуктом ООП в сочетании с практикой СУХОГО программирования. Определенно возможно создать простой в обслуживании процедурный код, который не вызывает кошмаров, и в равной степени возможно создание ужасного объектно-ориентированного кода. [ Pro PHP и jQuery ] попытаются продемонстрировать сочетание хороших навыков кодирования в сочетании с ООП для создания чистого кода, который легко читать и поддерживать.

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

А если вы хотите приобрести недорогие высококачественные PHP-скрипты , вы можете найти их в CodeCanyon .

Примечание автора — это руководство было выдержкой из Pro PHP и jQuery (Apress, 2010).