Чи справді оголошення PHP шкідливими для PHP?


13

Розглянемо наступний код, у якому сеттер навмисно порушується через повсякденну помилку програмування, яку я зробив реально кілька разів у минулому:

<?php

    class TestClass {

        private $testField;

        function setField($newVal) {
            $testField = $newVal;
            // deliberately broken; should be `$this->testField = $newVal`
        }

        function getField() {
            return $this->testField;
        }

    }

    $testInstance = new TestClass();
    $testInstance->setField("Hello world!");

    // Actually prints nothing; getField() returns null
    echo $testInstance->getField(); 

?>

Те, що я заявив $testFieldу верхній частині класу, допомагає приховати від мене цю помилку програмування. Якби я не оголосив це поле, я отримав би щось подібне до наступного попередження, надрукованого в моєму журналі помилок при виклику цього сценарію, що потенційно може бути корисним для моєї налагодження - особливо, якщо я можу зробити подібну помилку в великий і складний додаток у реальному світі:

Примітка PHP: Не визначена властивість: TestClass :: $ testField у /var/www/test.php у рядку 13

З декларацією попередження немає.

Можливо, мені чогось не вистачає, але мені відомо лише дві причини для оголошення класових полів у PHP: по-перше, що декларації виступають як документація, по-друге, що без декларацій не можна використовувати модифікатори privateта protectedдоступ до них, які є мабуть корисно. Оскільки останній аргумент не стосується публічних полів - присвоєння незадекларованому полю об’єкта робить його загальнодоступним - мені здається, що я повинен хоча б прокоментувати всі мої декларації на публічному полі. У коментарях буде вказано таке саме значення документації, але я отримаю користь від попереджень, якщо спробую прочитати неініціалізоване поле.

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

Що змушує мене вагатися, це те, що я ніколи не бачив, щоб хтось це робив у своєму коді. Чому ні? Чи є користь у оголошенні полів класу, про які я не знаю? Або я можу змінити конфігурацію PHP якимось чином, щоб змінити поведінку декларацій на місцях, щоб я міг використовувати реальні декларації поля та все-таки скористатися попередженнями "Не визначений властивість"? Або взагалі є щось інше, що я пропустив у своєму аналізі?


1
Можливо, корисно ? Вигоди, які ви заявили, надзвичайно важливі. Я, мабуть, категорично відмовився б працювати над кодом, який не мав явних декларацій про властивості.
Майкл

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

1
є вбудований звіт про помилки php (рівень сповіщення), який підкаже, чи використовуєте ви змінну, не попередньо оголошуючи її.
Crayon Violent

3
@MarkAmery Я б подумав, що запущений темп запуску є одним з найважливіших місць для прийняття суворого тестування одиниць - оскільки ви завжди змінюєте код, ви, ймовірно, завжди його порушуєте . Це дійсно точна мета суворого тестування та вирівнювання TDD. Так, я думаю, що підкреслення може допомогти вам пам'ятати, що ви отримуєте доступ до приватних речей, але для мене ідея прийняття конкретних стандартів кодування, щоб захистити мене від помилок, яких я не повинен робити, викликає занепокоєння. Як і робити, TRUE === $variableщоб запобігти випадковому призначенню замість порівняння.
Майкл

1
@MarkAmery Зауважте також, що ключові слова видимості аналізуються за допомогою автоматизованих інструментів документації , тому вони дають більше "значення документації", ніж просто коментар, який ви б додали вручну.
Майкл

Відповіді:


15

Ви завжди повинні декларувати властивості свого класу достроково. Незважаючи на те, що PHP - це динамічна мова і з радістю піде правильно разом із вами, створюючи свої властивості під час виконання, на цьому шляху є кілька недоліків.

  • Компілятор може оптимізувати заявлені властивості. Коли ви динамічно оголошуєте властивість, це хіт до продуктивності, оскільки компілятор повинен створити динамічну хеш-таблицю, щоб зберігати свої динамічні властивості.
  • Я не на 100% на цьому, але я вважаю, що оптимізатори байт-кодів, такі як APC, не будуть настільки корисними, оскільки не матимуть повного уявлення про ваш клас. (А оптимізатори, як APC, обов'язкові )
  • Робить код у 1000 разів важчим для читання. Люди будуть вас ненавидіти.
  • Робить це в 1000 разів більше шансів на те, що ви помилитесь. (Це було getId чи getID? Зачекайте, ви використали і те й інше. Fail.)
  • Немає автоматичного завершення або натяку на IDE.
  • Генератори документації не побачать вашу власність.

Проблема ви описали насправді є незначним у порівнянні з проблемою , НЕ оголошуючи свої властивості у визначенні вашого класу. Ось хороше рішення.

Звикайте до оголошення за замовчуванням своїх властивостей.

private $testField = null;
private $testField = '';
private $testField = 0;
private $testField = []; //array()
private $testField = false;

За винятком властивостей, які будуть зберігати об’єкти, це охоплює більшість базових типів, які ви будете зберігати. Властивості, які зберігатимуть об'єкти, можна встановити у вашому конструкторі.

Хорошим правилом для дизайну класів є те, що після того, як ваш об’єкт був створений і ваш конструктор запущений, у вас не повинно бути жодних властивостей там "невизначених".


У відповідь на ваші 5 недоліків: 1 (Продуктивність): Чи є у вас джерело для цього? 2 (читабельність): Не впевнений, що я розумію; пропозиція була для коментування декларацій, а не просто їх вилучення, тому яка читабельність втрачається? Мабуть, менш привітне виділення синтаксису та можливі труднощі відрізнити від сусідніх коментарів, я думаю? 3: Цей я взагалі не розумію; Ви можете уточнити? 4 (IDE): Досить справедливо - я не маю досвіду кодування PHP з IDE і не знав про натяк на тип Eclipse. 5 (генератори док): Досить справедливо - ніколи не використовував жодного з них.
Марк Амері

Я не бачив вашої лінії щодо коментування їх. Незважаючи на те, вищезазначені моменти все ще діють - як ви знаєте, які з них діють чи законно коментуються ??
Джеррод Кропива

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

2
@MarkAmery Ваша помилка програмування, по суті, означає помилку друку. У нас їх усі були, але ти намагаєшся тут підірвати бомбу, щоб вбити муху.
Джеррод Кропива

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

2

Я працював над деяким кодом, який використовував динамічно створені властивості об'єкта. Я вважав, що використання динамічно створених властивостей об’єкта досить круто (правда, на мій погляд). Однак моїй програмі було потрібно 7 секунд для запуску. Я видалив властивості динамічного об’єкта і замінив їх властивості об’єктів, оголошені як частина кожного класу (загальнодоступні в цьому випадку). Час процесора піднявся від понад 7 секунд до 0,177 секунди. Це досить суттєво.

Цілком можливо, що я робив щось не так у тому, як я використовував властивості динамічних об'єктів. Можливо також, що моя конфігурація якимось чином порушена. Звичайно, я повинен сказати, що на моїй машині у мене дуже проста конфігурація PHP ванілі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.