Новости

PHP :: Спадкування класів

  1. Конструктори і спадкування
  2. Виклик перевизначеного методу
  3. Модифікатори Public, Private і Protected: управління доступом до класів
  4. Методи як засіб доступу до властивостей

objects03

11

Спадкування - це механізм, за допомогою якого один або кілька класів можна отримати з деякого базового класу. Клас, який виходить в результаті успадкування від іншого, називається його підкласом. Цей зв'язок зазвичай описують за допомогою термінів "батьківський" і "дочірній". Дочірній клас походить від батьківського і успадковує його характеристики. Ці характеристики складаються з властивостей і методів. Зазвичай в дочірньому класі до функціональності батьківського класу (який також називають суперкласом) додаються нові функціональні можливості. Тому кажуть, що дочірній клас розширює батьківський.

Перш ніж приступити до вивчення синтаксису успадкування, давайте розглянемо проблеми, які воно допоможе нам вирішити. Давайте повернемося до класу ShopProduct (який ми створили в попередній статті). В даний час він є досить узагальненим. З його допомогою можна оперувати різними товарами:

Код PHP class ShopProduct {public $ title; public $ producerMainName; public $ producerFirstName; public $ price; function __construct ($ title, $ firstName, $ mainName, $ price) {$ this-> title = $ title; $ This-> producerMainName = $ mainName; $ This-> producerFirstName = $ firstName; $ This-> price = $ price; } Function getProducer () {return "{$ this-> producerFirstName} {$ this-> producerMainName}"; }} $ Product1 = new ShopProduct ( 'Собаче серце »,« Михайло', 'Булгаков', 5.99); $ Product2 = new ShopProduct ( 'Перший сніг »,« Група »,« Моральний кодекс ", 2.99); echo "Автор: <b>". $ product1-> getProducer (). "</ b> <br>"; echo "Виконавець: <b>". $ product2-> getProducer (). "</ b>";

На виході отримуємо наступне:

Висновок двох об'єктів розрізняються семантично (за змістом)

Як бачимо, поділ імені автора на дві частини в нагоді нам при роботі і з книгами, і з компакт-дисками. У цьому випадку ми можемо сортувати товари на прізвище автора (тобто по полю, який містить "Булгаков" і "Моральний кодекс"), а не по імені, в якому містяться незначні "Михайло" і "Група". Лінь - це відмінна стратегія проектування, тому на даному етапі вам не слід переживати з приводу використання класу ShopProduct для більш ніж одного типу товару.

Але якщо в нашому прикладі додати кілька нових вимог, то все відразу ускладниться. Уявіть, наприклад, що вам потрібно відобразити дані, специфічні для книг і компакт-дисків. Скажімо, для CD бажано вивести загальний час звучання, а для книг - загальна кількість сторінок. Звичайно, можуть бути й інші відмінності, але ці добре ілюструють суть проблеми. Як розширити наш приклад, щоб врахувати всі ці зміни? На думку відразу приходять два варіанти. По-перше, можна помістити всі дані в клас ShopProduct. По-друге, можна розбити ShopProduct на два окремих класи.

Давайте розглянемо перший підхід. Отже, ми об'єднуємо дані про книги та компакт-дисках в одному класі:

Код PHP class ShopProduct {public $ title; public $ producerMainName; public $ producerFirstName; public $ price; // Два нових властивості public $ playLength; public $ numPages; function __construct ($ title, $ firstName, $ mainName, $ price, $ numPages = 0, $ playLength = 0) {$ this-> title = $ title; $ This-> producerMainName = $ mainName; $ This-> producerFirstName = $ firstName; $ This-> price = $ price; // Розширюємо конструктор $ this-> numPages = $ numPages; $ This-> playLength = $ playLength; } Function getProducer () {return "{$ this-> producerFirstName} {$ this-> producerMainName}"; } // Два нових методу function getNumberOfPages () {return $ this-> numPages; } Function getPlayLength () {return $ this-> playLength; }}

Щоб продемонструвати великий обсяг виконуваної роботи з кодування, в даному прикладі були використані методи доступу до властивостей $ numPages і $ playLength. В результаті об'єкт, екземпляр якого створюється за допомогою такого класу, буде завжди містити надлишкові методи. Крім того, для CD екземпляр об'єкта потрібно створювати за допомогою безглуздого аргументу конструктора. Таким чином, для CD буде зберігатися інформація і функціональні можливості класу, що відносяться до книг (загальна кількість сторінок), а для книг - дані про час звучання CD. Ймовірно, поки ви можете з цим змиритися. Але що буде, якщо ми додамо більше типів товарів, причому кожен - з власними методами, а потім додамо більше методів для кожного типу? Наш клас буде ставати все більш складним і важким для використання.

Тому примусове об'єднання полів, що відносяться до різних товарах, в один клас призведе до створення занадто громіздких об'єктів із зайвими властивостями і методами. Але цим проблеми не обмежуються. З функціональністю теж виникнуть труднощі. Уявіть метод, який виводить коротку інформацію про товар. Скажімо, відділу продажів потрібна інформація про товар у вигляді одного рядка для використання в рахунку-фактурі. Вони хочуть, щоб ми включили в неї час звучання для компакт-диска і кількість сторінок для книг. Таким чином, при реалізації цього методу нам доведеться враховувати тип кожного товару. Для відстеження формату об'єкта можна використовувати спеціальний прапор. Наведемо приклад:

Код PHP function getSummaryLine () {$ base = "{$ this-> title} ({$ this-> producerMainName}, {$ this-> producerFirstName})"; if ($ this-> type == 'book') $ base. = ": {$ this-> numPages} стр."; else if ($ this-> type == 'cd') $ base. = ": Тривалість - {$ this-> playLength}"; return $ base; }

Як бачите, щоб правильно встановити значення властивості $ type, нам потрібно в конструкторі перевірити значення аргументу $ numPages. І знову клас ShopProduct став більш складним, ніж потрібно. У міру додавання додаткових відмінностей в формати або нових форматів, нам буде важко справлятися з реалізацією цього методу. Тому, мабуть, для вирішення даного завдання необхідно застосувати другий підхід.

Оскільки ShopProduct починає нагадувати "два класи в одному", ми повинні це визнати і створити два типи замість одного. Однак якщо ми будемо створювати два окремих класу (наприклад, CDProduct і BookProduct) то виникне надмірне дублювання, тому що в обох класах міститися деякі однакові властивості і методи. Нам потрібно створити загальну функціональність в одному місці, щоб уникнути дублювання, але в той же час зробити так, щоб при виклику методу, котрий виводить коротку інформацію про товар, враховувалися особливості форматування. Одним словом, нам необхідно використовувати спадкування.

Перший крок в побудові дерева спадкування - знайти елементи базового класу, які не відповідають один одному або якими потрібно оперувати інакше. Ми знаємо, що методи getPlayLength () і getNumberOfPages () суперечать один одному. Нам також відомо, що потрібно створити різні реалізації методу getSummaryLine (). Давайте використаємо ці відмінності як основу для створення двох похідних класів:

Код PHP class ShopProduct {public $ title; public $ producerMainName; public $ producerFirstName; public $ price; public $ playLength; public $ numPages; function __construct ($ title, $ firstName, $ mainName, $ price, $ numPages = 0, $ playLength = 0) {$ this-> title = $ title; $ This-> producerMainName = $ mainName; $ This-> producerFirstName = $ firstName; $ This-> price = $ price; $ This-> numPages = $ numPages; $ This-> playLength = $ playLength; } Function getProducer () {return "{$ this-> producerFirstName} {$ this-> producerMainName}"; } Function getSummaryLine () {$ base = "{$ this-> title} ({$ this-> producerMainName}, {$ this-> producerFirstName})"; return $ base; }} Class CDProduct extends ShopProduct {function getPlayLength () {return $ this-> playLength; } Function getSummaryLine () {$ base = "{$ this-> title} ({$ this-> producerMainName}, {$ this-> producerFirstName})"; $ Base. = ": Тривалість - {$ this-> playLength}"; return $ base; }} Class BookProduct extends ShopProduct {function getNumberOfPages () {return $ this-> numPages; } Function getSummaryLine () {$ base = "{$ this-> title} ({$ this-> producerMainName}, {$ this-> producerFirstName})"; $ Base. = ": {$ This-> numPages} стр."; return $ base; }}

Щоб створити дочірній клас, необхідно використовувати в оголошенні класу ключове слово extends. В даному прикладі ми створили два нових класу, BookProduct і CDProduct. Обидва вони розширюють клас ShopProduct.

Оскільки в похідних класах конструктори не визначаються, при створенні екземплярів об'єктів цих класів буде автоматично викликатися конструктор батьківського класу. Дочірні класи успадковують доступ до всіх методів типу public і protected батьківського класу (але не до методів і властивостей типу private). Це означає, що ми можемо викликати метод getProducer () для екземпляра об'єкта класу CDProduct, хоча метод getProducer () визначено в класі ShopProduct:

Код PHP $ product2 = new CDProduct ( 'Перший сніг »,« Група »,« Моральний кодекс ", 2.99, null, 55.01); echo "Виконавець: <b>". $ product2-> getProducer (). "</ b>";

Таким чином, обидва наших дочірніх класу успадковують поведінка загального батьківського класу. І ми можемо звертатися з об'єктом BookProduct так, як ніби це об'єкт типу ShopProduct. Зверніть увагу на те, що для забезпечення власної реалізації в обох класах CDProduct і BookProduct переопределяется метод getSummaryLine (). Похідні класи можуть розширювати і змінювати функціональність батьківських класів. І в той же час кожен клас успадковує властивості батьківського класу.

Реалізація цього методу в суперкласу може здатися надмірною, оскільки метод переопределяется в обох дочірніх класах. Проте ми надаємо базовий набір функціональних можливостей, який можна буде використовувати в новому дочірньому класі. Наявність цього методу в суперкласі також гарантує для клієнтського коду, що у всіх об'єктах типу ShopProduct буде присутній метод getSummaryLine (). Пізніше ви побачите, як можна виконати цю вимогу в базовому класі, котрі дають ніякої його реалізації. Кожен дочірній об'єкт класу ShopProduct успадкує все властивості свого батька. У власних реалізаціях методу getSummaryLine () для обох класів CDProduct і BookProduct забезпечується доступ до властивості $ title.

З поняттям спадкування відразу розібратися непросто. Визначаючи клас, який розширює інший клас, ми гарантуємо, що екземпляр його об'єкта визначається характеристиками спочатку дочірнього, а потім - батьківського класу. Щоб зрозуміти це, потрібно міркувати з точки зору пошуку. Коли Ви телефонуєте $ product2-> getProducer () інтерпретатор PHP не може знайти такий метод в класі CDProduct. Пошук закінчується невдачею, і тому використовується стандартна реалізація цього методу, задана в класі ShopProduct. З іншого боку, коли ми викликаємо $ product2-> getSummaryLine (), то інтерпретатор PHP знаходить реалізацію методу getSummaryLine () в класі CDProduct і викликає його.

Те ж саме вірно і щодо доступу до властивостей. При зверненні до властивості $ title в методі getSummaryLine () з класу BookProduct, інтерпретатор PHP не знаходить визначення цієї властивості в класі BookProduct. Тому він використовує визначення даного властивості, заданий в батьківському класі ShopProduct. Оскільки властивість $ title використовується в обох підкласах, отже, воно повинно визначатися в суперкласі.

Навіть побіжного погляду на конструктор ShopProduct досить, щоб зрозуміти, що в базовому класі як і раніше виконується доступ до тих даних, якими повинен оперувати дочірній клас. Так, конструктору класу BookProduct повинен передаватися аргумент $ numPages, значення якого заноситься в однойменну властивість, а конструктор класу CDProduct повинен обробляти аргумент і властивість $ playLength. Щоб домогтися цього, ми визначимо методи конструктора в кожному дочірньому класі.

Конструктори і спадкування

При визначенні конструктора в дочірньому класі ви берете на себе відповідальність за передачу необхідних аргументів батьківського класу. Якщо ж ви цього не зробите, то у вас вийде частково сконструйований об'єкт. Щоб викликати потрібний метод з батьківського класу, вам знадобиться звернутися до самого цього класу через дескриптор. Для цієї мети в PHP передбачено ключове слово parent.

Щоб звернутися до методу в контексті класу, а не об'єкта, слід використовувати символи "::", а не "->". Тому конструкція parent :: __ construct () означає наступне: "Викликати метод __construct () батьківського класу". Давайте змінимо наш приклад так, щоб кожен клас оперував тільки тими даними, які мають до нього відношення:

Код PHP class ShopProduct {public $ title; public $ producerMainName; public $ producerFirstName; public $ price; // Тут ми видалили два надлишкових властивості function __construct ($ title, $ firstName, $ mainName, $ price) {$ this-> title = $ title; $ This-> producerMainName = $ mainName; $ This-> producerFirstName = $ firstName; $ This-> price = $ price; } Function getProducer () {return "{$ this-> producerFirstName} {$ this-> producerMainName}"; } Function getSummaryLine () {$ base = "{$ this-> title} ({$ this-> producerMainName}, {$ this-> producerFirstName})"; return $ base; }} Class CDProduct extends ShopProduct {public $ playLength; // Конструктор класу CDProduct function __construct ($ title, $ firstName, $ mainName, $ price, $ playLength) {// Виклик базового конструктора parent :: __ construct ($ title, $ firstName, $ mainName, $ price); $ This-> playLength = $ playLength; } Function getPlayLength () {return $ this-> playLength; } Function getSummaryLine () {$ base = "{$ this-> title} ({$ this-> producerMainName}, {$ this-> producerFirstName})"; $ Base. = ": Тривалість - {$ this-> playLength}"; return $ base; }} Class BookProduct extends ShopProduct {public $ numPages; // Конструктор класу BookProduct function __construct ($ title, $ firstName, $ mainName, $ price, $ numPages) {// Виклик базового конструктора parent :: __ construct ($ title, $ firstName, $ mainName, $ price); $ This-> numPages = $ numPages; } Function getNumberOfPages () {return $ this-> numPages; } Function getSummaryLine () {$ base = "{$ this-> title} ({$ this-> producerMainName}, {$ this-> producerFirstName})"; $ Base. = ": {$ This-> numPages} стр."; return $ base; }}

Кожен дочірній клас викликає конструктор свого батьківського класу, перш ніж визначати власні властивості. Базовий клас тепер "знає" тільки про власні даних. Дочірні класи - це зазвичай "спеціалізації" батьківських класів. Як правило, слід уникати того, щоб давати батьківським класах будь-які особливі "знання" про дочірніх класах. У разі зміни ієрархії класів це часто призводило до проблем. Безліч помилок виникало через те, що програмісти, після безпосереднього зміни "батька" класу, забували оновити сам конструктор. А при використанні уніфікованого конструктора виклик батьківського конструктора parent :: __ construct () означає звернення безпосередньо до батьківського класу, незалежно від того, які зміни відбулися в ієрархії класів. Але, звичайно, потрібно подбати про те, щоб цього батьківського класу були передані правильні аргументи!

Виклик перевизначеного методу

Ключове слово parent можна використовувати в будь-якому методі, який перекриває свій еквівалент в батьківському класі. Коли ми переобумовленої метод, то, можливо, хочемо не видалити функції "батька", а, скоріше, розширити їх. Досягти цього можна, викликавши метод батьківського класу в контексті поточного об'єкта. Якщо ви знову подивіться на реалізації методу getSummaryLine (), то побачите, що значна частина коду в них дублюється. І краще цим скористатися, ніж відтворювати функціональність, вже розроблену в класі ShopProduct:

Код PHP class ShopProduct {... function getSummaryLine () {$ base = "{$ this-> title} ({$ this-> producerMainName}, {$ this-> producerFirstName})"; return $ base; }} Class CDProduct extends ShopProduct {... function getSummaryLine () {$ base = parent :: getSummaryLine (). ": Тривалість - {$ this-> playLength}"; return $ base; }} Class BookProduct extends ShopProduct {... function getSummaryLine () {$ base = parent :: getSummaryLine (). ": {$ This-> numPages} стр."; return $ base; }}

Ми визначили основні функції для методу getSummaryLine () в базовому класі ShopProduct. Замість того щоб відтворювати їх у підкласах CDProduct і BookProduct, ми просто викличемо батьківський метод, перш ніж додавати додаткові дані до підсумковому рядку.

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

Модифікатори Public, Private і Protected: управління доступом до класів

До сих пір ми явно чи неявно оголошували всі властивості як public (загальнодоступні). Такий тип доступу за умовчанням установлюється для всіх методів, а також властивостей, оголошених з використанням застарілого ключового слова var. Елементи класу можна оголосити як public (загальнодоступні), private (закриті) або protected (захищені). Нижче описана різниця між ними:

  • До загальнодоступних властивостям і методам можна отримувати доступ з будь-якого контексту.

  • До закритого властивості і методу можна отримати доступ тільки з того класу, в якому вони оголошені. Навіть підкласи даного класу не мають доступу до таких властивостей і методів.

  • До захищених властивостям і методам можна отримати доступ або з містить їх класу, або з його підкласу. Ніякому зовнішньому коду такий доступ не надається.

Чим це може бути нам корисно? Ключові слова, що визначають область видимості, дозволяють показувати тільки ті аспекти класу, які потрібні клієнтові. Це дозволяє створити ясний і зрозумілий інтерфейс для об'єкта.

Контроль доступу, що дозволяє забороняти клієнту доступ до деяких властивостях, допоможе також уникнути помилок в коді. Припустимо, ми хочемо зробити так, щоб в об'єктах типу ShopProduct підтримувалися знижки. Для цього можна додати властивість $ discount і метод setDiscount ():

Код PHP class ShopProduct {... public $ discount = 0; ... function setDiscount ($ num) {$ this-> discount = $ num; }}

Але тут у нас є проблема. Ми хочемо показати всім тільки скориговану ціну, але клієнт може легко обійти метод getPrice () (якщо визначити такий метод) і отримати доступ до властивості $ price:

Код PHP echo "Ціна - {$ product1-> price}";

В результаті буде виведена вихідна ціна, а не ціна зі знижкою, яку ми хочемо представити. Щоб запобігти цьому, можна просто закрити властивість $ price. Це дозволить заборонити клієнтам прямий доступ до нього, змушуючи використовувати метод getPrice (). Будь-яка спроба отримати доступ до властивості $ price з-за меж класу ShopProduct закінчиться невдачею. В результаті для зовнішнього світу це властивість припинить існування.

Але визначення властивостей як private - не завжди вдала стратегія, оскільки тоді дочірній клас не зможе отримати доступ до закритих властивостями. А тепер уявіть, що правила вашого бізнесу такі: при покупці тільки книг знижку на них робити не можна. Ми можемо перевизначити метод getPrice (), щоб він повертав властивість $ price без застосування знижки:

Код PHP // Клас BookProduct function getPrice () {return $ this-> price; }

Оскільки властивість $ price оголошено в класі ShopProduct з модифікатором private, а не в BookProduct, спроба в наведеному вище коді отримати до нього доступ закінчиться невдачею. Щоб вирішити цю проблему, потрібно оголосити властивість $ price захищеним (protected) і тим самим надати доступ до нього дочірнім класами. Пам'ятайте, що до захищеного властивості або методу можна отримати доступ з-за меж ієрархії того класу, в якому це властивість або метод були оголошені. Доступ до них можна отримати тільки з вихідного класу або його дочірніх класів.

Як правило, з'явилися помилок при доступі до властівостей або методів спріяє Створення добро захищений кодом. Спочатку зробіть властивості закритими або захищеними, а потім ослабляйте обмеження в міру необхідності. Багато (якщо не всі) методи в ваших класах будуть загальнодоступними, але, повторюю ще раз, якщо у вас є сумніви, обмежте доступ. Метод, який надає локальні функції іншим методам в класі, не потрібен користувачам класу. Тому Ви можете це зробити закритим або захищеним.

Методи як засіб доступу до властивостей

Навіть якщо в клієнтській програмі потрібно буде працювати зі значеннями, що зберігаються в екземплярі вашого класу, як правило, варто заборонити прямий доступ до властивостей цього об'єкта. Замість цього створіть методи, які повертають або встановлюють потрібні значення. Такі методи називають методами доступу (accessors) або одержувачами (getter) і установниками (setter).

Ви вже бачили одна перевага, яку дають методи доступу: їх можна використовувати для фільтрації значень властивостей в залежності від обставин, як було проілюстровано вище за допомогою методу getPrice (). Метод-установник може також використовуватися для примусового визначення типу властивості. Ми вже бачили, що для обмеження типу аргументів методу можна використовувати уточнення, але у нас немає безпосереднього контролю над типами властивостей.

У попередній статті ми наводили приклад класу ShopProductWriter, за допомогою якого виводилася інформація про об'єкти типу ShopProduct. Давайте спробуємо піти далі і зробити так, щоб клас ShopProductWriter міг виводити інформацію про будь-якій кількості об'єктів типу ShopProduct одночасно:

Код PHP class ShopProductWriter {public $ products = array (); public function addProduct (ShopProduct $ shopProduct) {$ this-> products [] = $ shopProduct; } Public function write () {$ str = ""; foreach ($ this-> products as $ product) {$ str. = "{$ product-> title}: <b> {$ product-> getProducer ()} </ b>; {$ product-> getPrice () } $ <br> "; } Echo $ str; }} $ Product1 = new BookProduct ( 'Собаче серце »,« Михайло', 'Булгаков', 5.99, 380); $ Product2 = new CDProduct ( 'Перший сніг »,« Група »,« Моральний кодекс ", 2.99, 55.01); $ Write = new ShopProductWriter (); $ Write-> addProduct ($ product1); $ Write-> addProduct ($ product2); $ Write-> write (); Виведення інформації про всі об'єкти класу ShopProduct за допомогою допоміжного класу ShopProductWriter

Тепер клас ShopProductWriter став набагато корисніше. Він може містити багато об'єктів типу ShopProduct і відразу виводити інформацію про всі їх. Але ми все ще повинні покладатися на те, що програмісти клієнтського коду будуть строго дотримуватися правил роботи з класом. Хоча ми надали метод addProduct (), ми не заборонили програмістам безпосередньо виконувати операції над властивістю $ products. В результаті можна не тільки додати об'єкт неправильного типу до масиву властивостей $ products, а й затерти весь масив і замінити його значенням елементарного типу. Щоб не допустити цього, потрібно зробити властивість $ products закритим:

Код PHP class ShopProductWriter {private $ products = array (); ...}

Тепер зовнішній код не зможе зашкодити масив властивостей $ products. Весь доступ до нього має здійснюватися через метод addProduct (), а уточнення типу класу, які використовуються в оголошенні цього методу, гарантують, що до масиву властивостей можуть бути додані тільки об'єкти типу ShopProduct.

І на закінчення давайте змінимо клас ShopProduct і його дочірні класи так, щоб обмежити доступ до властивостей:

Код PHP class ShopProduct {private $ title; private $ producerMainName; private $ producerFirstName; private $ discount; protected $ price; function __construct ($ title, $ firstName, $ mainName, $ price) {$ this-> title = $ title; $ This-> producerMainName = $ mainName; $ This-> producerFirstName = $ firstName; $ This-> price = $ price; } Public function getPrice () {return $ this-> price; } Public function getProducerMainName () {return $ this-> producerMainName; } Public function getProducerFirstName () {return $ this-> producerFirstName; } Public function setDiscount ($ num) {$ this-> discount = $ num; } Public function getDiscount () {return $ this-> discount; } Public function getTitle () {return $ this-> title; } Public function getProducer () {return "{$ this-> producerFirstName} {$ this-> producerMainName}"; } Function getSummaryLine () {$ base = "{$ this-> title} ({$ this-> producerMainName}, {$ this-> producerFirstName})"; return $ base; }} Class CDProduct extends ShopProduct {private $ playLength = 0; function __construct ($ title, $ firstName, $ mainName, $ price, $ playLength) {parent :: __ construct ($ title, $ firstName, $ mainName, $ price); $ This-> playLength = $ playLength; } Function getPlayLength () {return $ this-> playLength; } Function getSummaryLine () {$ base = parent :: getSummaryLine (). ": Тривалість - {$ this-> playLength}"; return $ base; }} Class BookProduct extends ShopProduct {private $ numPages = 0; function __construct ($ title, $ firstName, $ mainName, $ price, $ numPages) {parent :: __ construct ($ title, $ firstName, $ mainName, $ price); $ This-> numPages = $ numPages; } Function getNumberOfPages () {return $ this-> numPages; } Function getSummaryLine () {$ base = parent :: getSummaryLine (). ": {$ This-> numPages} стр."; return $ base; }} Class ShopProductWriter {private $ products = array (); public function addProduct (ShopProduct $ shopProduct) {$ this-> products [] = $ shopProduct; } Public function write () {$ str = ""; foreach ($ this-> products as $ product) {$ str. = "{$ product-> getTitle ()}: <b> {$ product-> getProducer ()} </ b>; {$ product-> getPrice ()} $ <br> "; } Echo $ str; }}

У цій версії сімейства класів ShopProduct немає нічого істотно нового. Всі методи були явно зроблені загальнодоступними, а все властивості тепер стали або закритими, або захищеними. І для завершеності ми додали ряд методів доступу.

Класи і об'єкти Розширені можливості використання об'єктів Оцініті статтю:Як розширити наш приклад, щоб врахувати всі ці зміни?
Але що буде, якщо ми додамо більше типів товарів, причому кожен - з власними методами, а потім додамо більше методів для кожного типу?
Чим це може бути нам корисно?

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

Или позвоните нам по телефонам: (048) 823-25-64

Организация (обязательно) *

Адрес доставки

Объем

Как с вами связаться:

Имя

Телефон (обязательно) *

Мобильный телефон

Ваш E-Mail

Дополнительная информация: