Начало

Има твърде много остаряла информация в уеб-пространството, която заблуждава начинаещите PHP програмисти и ги кара да следват лоши практики и да пишат некачествен/несигурен код. Това трябва да престане. PHP: The Right Way е лесно за четене ръководство към най-добрите практики в PHP, приети стандарти за писане на код, както и връзки към качествени ръководства в Интернет.

Няма единен начин за работа с PHP. Този уебсайт цели да запознае начинаещите PHP програмисти с теми, които може да не открият навреме, и да даде на опитните програмисти някои свежи идеи по същите теми, за които не са преосмисляне с години. Този уебсайт, още, няма да ви каже кои инструменти да използвате, a вместо това ще предложи различни подходи и ще се опита да обясни разликите между тях.

Този документ не е статичен и ще продължи да се обновява с още полезна информация и примери.

Преводи

PHP: The Right Way е (или скоро ще бъде) преведено на много различни езици:

Как да допринесеш?

Помогни да направим този уеб сайт най-добрият източник за нови PHP програмисти! Допринеси в GitHub

Разпространи идеята!

PHP: The Right Way има банери и снимки които можете да сложите на вашият уебсайт. Покажете подкрепата си и насочете новите PHP програмисти към точното място за качествена информация по темата!

Разгледай банерите

Нагоре

Първи стъпки

Използване на последната стабилна версия (5.6)

Ако сега започвате с PHP бъдете сигурни, че ползвате последната версия - PHP 5.6. PHP направи големи крачки в добавянето на големи нови възможности в последните няколко години. Нека малката разлика във версията между 5.2 и 5.4 не Ви заблуждава, това са сериозни подобрения. Ако търсите фунцкия или как да я ползвате, документацията на php.net ще ви предостави отговора.

Вграден уеб сървър

Можете да започнете изучаването на PHP без да се налага да инсталирате или конфигурирате пълен уеб сървър. Единственото изискване е да имате PHP 5.4 или нагоре. За да стартирате вградения сървър, намирайки се в уеб директорията, трябва да напишете следното в терминала/командния ред:

> php -S localhost:8000

Настройка за Mac

OSX идва с пакет на PHP, който обикновено не е последната версия на PHP. Lion идва с PHP 5.3.6, Mountain Lion е с 5.3.10.

Можете да обновите PHP на OSX чрез множество Mac пакетни мениждъри, като php-osx от Liip е препоръчителен.

Друга възможност е да си го компилирате сами, в този случай трябва да сте инсталирали предварително или Xcode или заместващите го “Command Line Tools for Xcode” от Mac Developer Center на Apple.

За пълен “всичко в едно” пакет, включващ PHP, Apache уеб сървър и MySQL базаданни, всичко това с приятено графично приложение за управление, пробвайте MAMP.

Mac Setup

OSX идва с пакет на PHP, който обикновено не е последната версия на PHP. Lion идва с PHP 5.3.6, Mountain Lion е с 5.3.10. Mavericks е с 5.4.17 и Yosemite - 5.5.9, но в повечето случаи това не е достатъчно, тъй като PHP 5.6 е вече на лице.

Има няколко начина за инсталиране на PHP под OS X.

Инсталиране на PHP чрез Homebrew

Homebrew е пакетен мениджър с множество възможности за OS X, който може да ви помогне да инсталирате лесно PHP и редица други разширения. Homebrew PHP е хранилище, което съдържа пакети свързани с PHP за Homebrew, също ще ви позволи да инсталирате PHP.

Към момента, може да инсталирате php53, php54, php55 или php56 използвайки brew install командата и да ги сменяте като променяте вашата PATH променлива. Другия вариант е да използвате brew-php-switcher, което ще смени версията автоматично вместо вас.

Инсталиране на PHP чрез Macports

MacPorts проектът е open-source инициатива да предостави лесна за използване система за компилиране, инсталиране и надграждане на терминала, X11 или Aqua базиран open-source софтуер под OS X.

Macports поддържа предварително компилирани бинарни файлове, така не ви се налага да компилирате наново всяка зависимост от source tarball файлове, спасява ви живота, ако нямате нито един пакет инсталиран на система ви.

Към момента, може да инсталирате php53, php54, php55 или php56 чрез port install командата:

sudo port install php54
sudo port install php55

И може да изпълните select командата, за да превключите на друга PHP версия:

sudo port select --set php php55

Инсталиране на PHP чрез phprew

phpbrew е инструмент за инсталиране и менажиране на множество PHP версии. Това би било полезно, ако два различни проекта/приложения изискват различна версия на PHP и вие не използвате виртуални машини.

Инсталиране на PHP чрез Liip’s binary installer

Друга известна опция е php-osx.liip.ch което дава възможност за инсталация на PHP (от версия 5.3 до версия 5.6) само с една команда. Този метод не презаписва бинарните файлове на php инсталирани от Apple, но инсталира всичко в отделна директория (/usr/local/php5).

Компилиране от Source Code

Друга възможност, която ви дава избор върху версията на PHP, която инсталирате, е да компилирате PHP сами. В този случай задължително трябва да имате инсталиран Xcode или заместника му “Command Line Tools for XCode”, които са достъпни в Apple’s Mac Developer Center.

All-in-One Installers

Решенията изброени по-горе главно инсталират единствено PHP и не осигуряват други приложения като Apache, Nginx или SQL сървър. “All-in-one” решенията като MAMP и XAMPP ще инсталират останалия необходим софтуер, който в повечето случаи се изисква от стандартните PHP приложения. Но за сметка на това улеснение, се губи голяма част от гъвкъвоста върху PHP и неговите версии.

Настройка за Windows

Има няколко начина за инсталиране на PHP под Windows. Можете да изтеглите бинарните (компилираните) файлове и до скоро можехте да ползвате ‘.msi’ инсталационна програма. Инсталационната програма вече не се поддържа и е спряна от PHP 5.3.0.

За обучение, експерименти и локална разработка може да ползвате вграденият уеб сървър с PHP 5.4, като няма да се тревожите за конфигурирането му. Ако желаете “всичко в едно” решение, което включва пълен уеб сървър и MySQL, тогава инструментите Web Platform Installer, Zend Server CE,

XAMPP и WAMP ще ви помогнат с бързото установяване на среда за разработка под Windows. Към това трябва да добавим, че тези инструменти се различават от тези на реалните сървъри, така че трябва да внимавате с различията в средата, ако разработвате под Windows, но внедрявате на Linux. Ако реалната ви система трябва да работи на Windows, тогава IIS7 ще ви предостави най-добра производителност и стабилност. Можете да ползвате phpmanager (графичнa приставка IIS7) за проста настройка и управление на PHP simple. IIS7 идва с вграден и готов за ползване FastCGI, само трябва да се настрои PHP като манипулатор (handler). Поддръжка и допълнтелни ресури можете да намерите на iis.net.

Vagrant

Обикновено когато пускате приложенията си на различни среди при разработа и на реалните сървъри може да доведе до странни проблеми (бъгове), които се появяват след като се внедри приложението. Ако разработвате на Windows и внедрявате на Linux (или нещо което не е Windows), тогава трябва да обмислите ползването на виртуална машина. Това звучи сложно, но ако използвате Vagrant можете да настроите просто обвивки (wrappers), тогава използвайки Puppet или Chef можете да подсигурите тези машини и да ги споделите с колегите, за да сте сигурни, че работите всички в една и съща среда, избягвайки множество сложни настройки. Освен това може да “унищожите” вашата виртуална машина и да я “построите” лесно отново, което ви дава “прясна” инсталация.

Vagrant създава обща директория, предназначена за споделяне на кода ви между хостинга и виртуалната ви машина. Това означава, че можете да редактирате файловете си на хостинг машината си, а след това да изпълните файловете на виртуалната машина.

Нагоре

Ръководство за стил на писане на код

PHP обществото е голямо и разнообразно, създало е неизброимо много библиотеки, рамки (frameworks) и компоненти. Често срещано е PHP разработчик да избере няколко стандарта и да ги обедини в един проект. Затова e важно PHP кода да се придържа (възможно най-много) до един общ стил на писане на код, за да е лесно за разработчиците да смесват код от различни библиотеки за техните проекти.

Framework Interop Group (преди това известна като “PHP Standards Group”) предложи и одобри серия от препоръки за стил, известни като PSR-0, PSR-1 и PSR-2. Нека интересните имена не ви заблуждават, това са препоръки съдържащи набор от правила за писане на код, които започват да се използват от някои проекти, като Drupal, Zend, CakePHP, phpBB, AWS SDK, FuelPHP, Lithium и др. Можете да ги използвате за вашите собствени проекти или да продължите да ползвате свой собствен стил.

В най-добрия случай, пишейки код трябва да се придържате към определен стандарт. Това може да бъде всяка комбинация от PSR, или някой от стандартите създадени от PEAR или Zend.Това ще направи приложенията ви по-консистентни и ще позволи на други разработчици да четат по-лесно кода ви и да работят с него.

Можете да ползвате PHP_CodeSniffer, за да проверявате код за съответствие със стандартите, както и приставки към редактори, като Sublime Text 2, за резултати в реално време.

Използвайте PHP Coding Standards Fixer на Fabien Potencier който редактира вашия код, така че да отговаря на стандартите и решава проблема с оправянето на всяко разминаване от стандарта самостоятелно.

Английския език е препоръчителен за всички имена на символи и структури. Коментарите могат да се пишат на всеки език, стига да са лесни за четене от всички настоящи и бъдещи потребители, които биха работили с кода.

Нагоре

Акценти от възможностите на езика PHP

Парадигми за програмиране

PHP е гъвкав, динамичен език, който поддържа множество техники за програмиране. През последните години PHP еволюира много, особено с добавянето на солиден обектно-ориентиран модел в PHP 5.0 (2004), анонимни функции и области от имена (namespaces) в PHP 5.3 (2009), и трейтове (traits) в PHP 5.4 (2012).

Обектно-ориентирано програмиране

PHP има много пълен набор от възможности за обектно-ориентирано програмиране, включващо поддръжка на класове, абстрактни класове, интерфейси, наследяване, конструктори, клониране, изключения и др.

Фукционално програмиране

PHP поддържа функции от първи клас, което ознавача, че функциите могат да бъдат присвоявани на на променливи. Както дефинираните от потребителя, така и вградените функции могат да бъдат посочени от променлива и да бъдат извикани динамично. Функциите могат да бъдат предавани като аргументи на други функции (възможността се нарича функции от висок ред) и функция също може да върне фунцкия.

Рекурсията е възможността фунцкия да извика сама себе си. Това се поддържа от езика PHP, но повечето PHP код набляга на итерацията.

Анонимните функции (с поддръжка на затваряне (closures)) са възможни от PHP 5.3 (2009).

В PHP 5.4 се добавя възможността да обвържеш затваряне към областта на видимост (scope) на обект, също и поддръжка за извикваеми обекти, които са взаимнозаменими с анонимни фунцкии в почти всички случаи.

Метапрограмиране

PHP поддържа различни форми на метапрограмиране чрез механизми като API за отражение (reflection) и вълшебни методи. Има доста вълшебни методи __get(), __set(), __clone(), __toString(), __invoke() и др. които позволяват на разработчиците да закачат поведение на клас. Руби разработчиците често казват, че PHP няма method_missing, но това всъщност е възможно чрез __call() и __callStatic().

Пространствата от имена* (namespaces)

Както е споменато по-горе, PHP общността има много разработчици, създаващи много код. Това означава, че една библиотека може да има един и същи клас като друга библиотека. Когато двете библиотеки са използвани в едно и също пространство от имена, те се сблъскват и изниква грешка.

Областите от имена решават този проблем. Както е описано в ръководството на PHP, областите от имена могат да бъдат сравнени като директории в операционна система; два файла със едно и също име могат да съществуват в различни директории. Аналогично, два класа в PHP могат да съществуват едновременно в отделни области от имена.

Важно е да поставите кода си в област от имена, за да може другите разработчици да ползват вашия код, без да се страхуват от сблъсък/препокриване на имена.

Един от препоръчителните начини е описан в PSR-0, който цели да предостави стандартна конвенция за имената на файл, клас и област от имена за да предостави лесен за вграждане код.

* Терминът е взет от документацията на php.net. Често се ползват и термините “именовани пространства” и “области от имена” да означат същото нещо.

Стандартната PHP библиотека

Стандартната PHP библиотека (SPL, standard php library) е пакетирана с PHP и предоставя набор от класове и интерфейси. Съставена е основно от класове на често необходими структури от данни (стек, опашка, двоична пирамида и т.н.), и итератори, които могат да ги обхождат.

Команден ред

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

CLI PHP програмите са мощни, защото може да се изпозлва кода на приложението без да се създава сигурен уеб интерфейс за него. Просто не трябва да слагате CLI PHP скриптовете в публична уеб директория!

Стартирайте PHP от командния ред:

> php -i

Опцията -i ще отпечата конфигурацията на PHP точно както фунцията phpinfo.

Опцията -a предоставя интерактивен шел (команден интерфейс), подобен на IRB на Руби или интерактивния шел на Питон. Има и други полезни опции в командия режим.

Нека напишем проста “Hello, $name” CLI програма. Създайте файл hello.php със следното съдържание:

<?php
if ($argc != 2) {
    echo "Usage: php hello.php [name].\n";
    exit(1);
}
$name = $argv[1];
echo "Hello, $name\n";

PHP настройва две специални променливи въз основа аргументите, предадени на скрипта, който пускате. $argc е целочислена променлива, съдържаща броя на аргументите, а $argv е променлива масив, която съдържа стойността на всеки аргумент. Първият аргумент ($argv[0]) е винаги името с което е стартиран вашия скрипт, в този случай hello.php.

Изразът exit() се използва с положителна числена стойност, за да извести командния ред, че е настъпила грешка. Най-често срещаните стойности на изход могат да бъдат намерени тук

За да стартирате скрипта по-горе, напишете в командия ред:

> php hello.php
Usage: php hello.php [name]
> php hello.php world
Hello, world

Нагоре

Управление на зависимостите

Има хиляди PHP библиотеки, рамки и компоненти, които можеш да избереш. Твоят проект вероятно ще включва няколко от тях — това са зависимости на проекта. До скоро, PHP не притежаваше добър начин за управление на тези проектни зависимости. Дори и ако ги настроите ръчно, вие все още трябва да се грижите за автоматичните зареждачи (autoloaders). Но вече не.

В момента има две основни системи за управление на пакети за PHP - Composer и PEAR. Коя е по-подходяща за вас? Отговорът е - и двете.

Общо казано, Composer пакетите ще са достъпни в проектите където вие изрично ги опоменете, докато PEAR пакетите ще достъпни за всичките ви PHP проекти. На пръв поглед PEAR може да взучи като по-лесния подход, но има предимства при ползването на настройки на зависимостите проект за проект.

Composer и Packagist

Composer е брилянтна система за управление на зависимости за PHP. Изпишете проектните зависимости в файл composer.json и с няколко команди, Composer автоматично ще свали и настрои проектните зависимости вместо вас.

Вече има предостатъчно PHP библиотеки, които са съвместими с Composer, готови за ползване във вашия проект. Тези “пакети” са описани в списъка на Packagist, официалното хранилище за Composer-съвместими PHP библиотеки.

Как да инсталираме Composer

Можете да инсталирате Composer локално (в текущата директория; но вече не се препоръчва) или глобално (например /usr/local/bin). Нека допуснем, че желаете да инсталирате Composer локално. От директорията на проекта изпълнете:

curl -s http://getcomposer.org/installer | php

Това ще изтегли composer.phar (изпълним PHP архив). Можете да стартирате файла с php за да управлявате зависимостите си. Забележка: Ако сваленият код го пренасочите директно към интерпретатора, чрез pipe |, моля първо прочетете кода онлайн за да подвърдите, че е сигурен (не е зловреден).

Как да инсталираме Composer (ръчно)

Ръчното инсталиране на Composer техника за напреднали; въпреки това, има множество причини заради които разработчика може да предпочете този метод пред използването на интерактивна инсталация. Интерактивната инсталация проверява вашата PHP инсталация дали:

Ръчната инсталация не прилага нито една от тези проверки, затова вие трябва да решите дали тя е по-подходяща за вас. А ето как да се сдобиете с Composer ръчно:

curl -s http://getcomposer.org/composer.phar -o $HOME/local/bin/composer
chmod +x $HOME/local/bin/composer

Пътят $HOME/local/bin (или избраната от вас директория) трябва да се намира в променливата в средата $PATH. Това ще направи composer достъпен от командния ред.

Когато се натъкнете на документация, която пише да ползвате Composer, като php composer.phar install, може да го замените с:

composer install

Как да описваме и инсталираме зависимости

Първо създайте файл composer.json в същатата директория, като composer.phar. Ето пример за списък, кото описва Twig като зависимост за проекта.

{
    "require": {
        "twig/twig": "1.8.*"
    }
}

След това, изпълнете командата от проектната директория.

php composer.phar install

Това ще изтегли и инсталира проектните зависимости в директория vendors/. След това, добавете тази линия към основния файл на вашия проект; това ще каже на PHP да ползва атоматичния зареждач (autoloader) на Composer за вашите проектни зависимости.

<?php
require 'vendor/autoload.php';

Вече можете да използвате вашите проектни зависимости и те ще се зареждат при нужда.

PEAR

PEAR е ветеран в системите за управление на зависимости, който много PHP разработчици обичат. Държи се по подобен начин и си заслужава изследването му за ползване във вашите проекти. Научи за PEAR.

XDebug

Един от най-полезните инструменти при разработването на софтуер е добрия дебъгер (debugger). Той ви позволява да проследявате изпълнението на вашия код и да наблюдавате съдържанието на стека. XDebug, дебъгера на PHP, може да бъде използван от много интегрирани среди за разработка (IDE), предоставяйки точки на прекъсване (breakpoints) и инспектиране на стека. Също така XDebug позволява на инструменти, като PHPUnit и KCacheGrind да създават анализ и профилиране на кода.

Ако се намирате в затруднение, ползвате var_dump/print_r, но все пак не можете да откриете проблема, вероятно трябва да ползвате дебъгера.

Инсталирането XDebug може да бъде пипкаво, но едно от най-полезните му свойства е “Отдалеченото отстраняване на грешки” (Remote Debugging). Ако пишете код локално, а след това тествате на виртуална машина, или на друг сървър, отдалеченото дебъгване е опцията, която ще желаете да включите.

Обикновено, ще промените конфигурацията на виртуалния си хост, или .htaccess файла си със следните стойности:

php_value xdebug.remote_host=192.168.?.?
php_value xdebug.remote_port=9000

“remote_host” и “remote_port” отговарят на IP адреса на вашия компютър и порта, на който редактора ви ще “слуша”. След това всичко е въпрос на поставяне на редактора в “режим на слушане” и зареждане на адреса:

http://your-website.example.com/index.php?XDEBUG_SESSION_START=1

Вашия редактор ще прекрати нормалното изпъление на скрипта, позволявайки ви да поставите точки на прекъсване и да следите стойностите в паметта.

Нагоре

Добри практики за код

Основите

PHP е обширен език, кото позволява на програмистите от всяко ниво взможността да създават код, не само бързо но и ефективно. За съжаление, с напредването ни в езика, ние често забравяме за основите, които първо сме научили (или пренебрегнали) за сметка на бързите решения и лошите навици. За да се борите с този въздесъщ проблем, тази секция е сложена за да припомня на програмистите за основите за писане на код в PHP.

Дата и час

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

За да започнете работата с DateTime, преобразувайте сурова дата и час в обект чрез createFromFormat() метод фабрика или чрез new \DateTime за да вземете текущата дата и час. Изпозлвайте метода format() за да преобразувате DateTime обратно в низ за изход.

<?php
$raw = '22. 11. 1968';
$start = \DateTime::createFromFormat('d. m. Y', $raw);

echo 'Start date: ' . $start->format('m/d/Y') . "\n";

Сметките с DateTime се правят чрез класа DateInterval. Методите като add() и sub() на класа DateTime взикат DateInterval за аргумент. Не пишете код който очаква определен брой секунди всеки ден, смятата на зимно и лятно време, катко и промяната на часовия пояс може да доведе до грешка. Използвайте интервали от време вместо това. За да изчислите разликата между две дати, използвайте diff() метода. Той ще върне нов DateInterval обект, който е много лесен за показване.

<?php
// create a copy of $start and add one month and 6 days
$end = clone $start;
$end->add(new \DateInterval('P1M6D'));

$diff = $end->diff($start);
echo 'Difference: ' . $diff->format('%m month, %d days (total: %a days)') . "\n";
// Difference: 1 month, 6 days (total: 37 days)

На обекти от тип DateTime можеш да прилагаш обикновено сравненеие:

<?php
if ($start < $end) {
    echo "Start is before end!\n";
}

Един последен пример ще демонстрира класа DatePeriod. Той се използва за обхождане на повтарящи се събития. Може да приеме два DateTime обекта, т.е. начало и край и интервал интервал, и ще върне всички обекти по средата.

<?php
// output all thursdays between $start and $end
$periodInterval = \DateInterval::createFromDateString('first thursday');
$periodIterator = new \DatePeriod($start, $periodInterval, $end, \DatePeriod::EXCLUDE_START_DATE);
foreach ($periodIterator as $date) {
    // output each date in the period
    echo $date->format('m/d/Y') . ' ';
}

Шаблони за дизайн

Когато създавате приложение е полезно да ползвате, често срещани шаблони в кода и в общата структура на проекта. Изпозлването на шаблони е полезно защото прави кода много по лесен за управление и поддръжка и позволява на разработчиците лесно да разберат как всичко се връзва помежду си.

Ако ползвате рамка (фреймуорк), тогава по-голяма част от кода от високо ниво и проектната структура ще са базирани на рамката, така че голяма част от решенията за шаблони са взети вместо вас. Но въпреки това остава вие да изберете най-добрите за вас шаблони, когато става дума за код. Ако от друга страна не ползвате рамка, то тогава трябва да подберете такива шаблони, които да пасват на типа и размера на приложението което изграждате.

Изключения (Exceptions)

Изключенията са стандартна част от повечето популярни програмни езици, но често са пренебрегвани от PHP програмистите. Езици като Ruby са крайно насочени към изключенията, т.е. дори ако нещо се случи, като провалена HTTP заявка или заявка към БД даде грешка или дори статична картина не може да бъде намерена, Ruby (или gem-а, който се ползва) ще хвърли изключение към екрана, и на момента разбираш, че е настъпила грешка.

При PHP по принцип, често липсва тази възможност, и примерно проблемно извикване на file_get_contents() ще върне FALSE и ще изведе предупреждение. Много стари рамки като CodeIgniter ще върнат false, и ще запишат съобщение в log-а и вероятно ще предоставят метод, като $this->upload->get_error() за да видиш каква е грешката. Проблема възниква в това, че трябва да отидете в документацията и да проверите какъв е метода за грешка за този клас вместо да бъде максимално видима грешката.

Друг проблем когато клас направиш клас автоматично след като изведе грешката на екрана да излезе от цялата програма. Когато се прави това вие пречите на друг разработчик, динамично да обработи грешката. Изключенията трябва да бъдат хвърляни за да се извести разработчика че е настъпила грешка, тогава той може да реши как да я обработи, пример:

<?php
$email = new Fuel\Email;
$email->subject('My Subject');
$email->body('How the heck are you?');
$email->to('guy@example.com', 'Some Guy');

try
{
    $email->send();
}
catch(Fuel\Email\ValidationFailedException $e)
{
    // The validation failed
}
catch(Fuel\Email\SendingFailedException $e)
{
    // The driver could not send the email
}

SPL изключения

Изключението по поддразбиране няма значение и най-практикувания начин е като им се даде име:

<?php
class ValidationException extends Exception {}

Това означава, че вие можете да добавите множесто блокове, които да се справят с изключенията по различен начин. Това може да доведе до много видове изключения, някои от които могат да бъдат избегнати с SPL изключения предоставени в разширението SPL.

Например позлвате вълшебния метод __call() и невалиден метод е поискан, вместо да хвърляте обикновено изключение, или да създавате специален тип изключение за това, можете просто да throw new BadFunctionCallException;.

Нагоре

Бази данни

Много пъти вашият PHP код ще ползва база от данни за да записва информацията. Имате няколко избора за свързване и работа с вашата база данни. Препоръчителната опция до PHP 5.1.0 беше да се ползват естествените разширения mysql, mysqli, pgsql и др.

Естествените драйвери са страхотни, ако ползвате само ЕДНА база данни в вашето приложение, но ако например ползвате MySQL и малко MSSQL, или имате нужда да се свържете с база от данни на Oracle, тогава няма да имате взможността да ползвате едни и същи драйвери. Ще трябва да се запознаете с чисто ново API за всяка един тип база от данни — и това може да създаде много проблеми.

Допълнителна бележка към естествените драйвери: mysql разширението за PHP вече не се разработва активно, и официалното състояние в версия PHP 5.4.0 е “В дълъг процес на премахване”. Това означава че ще бъде премахнат в следващите няколко версии, т.е. до PHP 5.6 (или което идва след 5.5) може би вече няма да го има. Ако ползвате mysql_connect() и mysql_query() във вашите приложения, тогава ще трябва да ги пренапишете по някое време, като най-доброто решение е да заместите ползването на mysql с mysqli или PDO още по време на процеса на разработа за да не се налага да бързате впоследствие. Ако започвате от начало, то тогава изобщо не трябва да ползвате разширението mysql: ползвайте MySQLi extension или PDO.

PDO

PDO е библиотека за абстрация на връзката с база данни — вградена в PHP от версия 5.1.0 — която предоставя общ интерфейс за работа с много различни бази от данни. PDO не превежда/транслира вашите заявки и не емулира липсващи възможности, та служи само за свързване с множество типове разлини бази от данни изпозлвайки общо API.

По-важно, PDO ти позволява да безопасно да вкарваш външен вход (параметри, подадени от потребителя) в SQL заявките без да се притесняваш от SQL injection. Това е възможно чрез параметризирани заявки (PDO statement) и обвързани параметри (bound parameters).

Нека предположим, че PHP скрипт получава числово ID като параметър на заявката. Това ID трябва да се използва за извличането на потребителски запис от базата. Това е грешният начин да постигнете това:

<?php
$pdo = new PDO('sqlite:users.db');
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!

Този код е ужасен. Така вие вкарвате суров параметър в заявката. По този начин ще бъдете хакнати за нула време. Просто си представете как хакер предава id параметър като изпозлва URL подобен на http://example.com/?id=1%3BDELETE+FROM+users. Това ще зададе $_GET['id'] стойност id=1;DELETE FROM users което ще изтрие всички ваши потребители! Вместо това, вие трябва да филтрирате ID-то от входа, изпозлваки PDO обвързани параметри (bound parameters).

<?php
$pdo = new PDO('sqlite:users.db');
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
$stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT); //<-- Automatically sanitized by PDO
$stmt->execute();

Това е правилният начин. Използва обвързан параметър към PDO параметризирана заявка. Това екранира външния вход за ID преди да бъде предаден на базата данни и предотвратява SQL injection.

Трябва също да знаете, че връзките към базата данни използват ресурси и е имало проблеми с липса на достатъчно ресурси, когато не се затварят връзки към базата данни или заявки, но това е по-често за другите програмни езици. Изпозлването на

PDO може неуказано да затвори възка, при унищожаването на обект за да осигури всички синоними (референции) на обекта да са изтрити, т.е. със стойност NULL. Ако не направите това изрично, PHP автоматично ще затвори връзката, когато скрипта приключи, освен ако не ползвате постоянни връзки (persistent connections).

Слоеве на абстракция

Много рамки ползват обствен слой на абстракция, който може или не може да бъде надграден върху PDO. Те обикновено емулират възможности на на други бази, които са достъпни за едни, но не и за други, като обвиват заявките в PHP методи, давайки реална абстракция на базата данни. Това естествено добавя малко режиен (overhead), но ако разработвате преносимо (съвместимо с множество платформи) приложение, което трябва да работи с MySQL, PostgreSQL и SQLite, тогава малко (най-често незабележимо) забавяне ще си струва за сметка на подредения и чист код.

Някои слоеве на абстракция са направени в съответствие с PSR-0 конвенцията на пространства от имена и могат да бъдат инсталирани в приложението ви, примери:

Нагоре

Сигурност

Сигурност на уеб приложенията

Има лоши хора, които са готови да хакнат вашите приложения. Много е важно вие да вземете необходимите мерки за да подсилите сигурността на вашето приложение. За щастие, хората от The Open Web Application Security Project (OWASP) са съставили пълен списък с известните проблеми в сигурността и методи за защита от тях. Това трябва да се прочете от всеки запознат със сигурнсотта програмист.

Хеширане на пароли чрез Bcrypt

В края на краищата всеки изгражда PHP приложение което зависи от потребителски вход. Потребителите и (хешираните) паролите се съхраняват в база от данни и после се ползват за удостоверяване (автентикиране) на потребителите при вход.

Много е важно да хеширате правилно паролите които се пазят в базата данни. Ако паролите не са хеширани и базата ви е хакната или свалена от неоторизирано трето лице, всички потребителски профили/акаунти са компроментирани.

Хеширане на пароли чрез Bcrypt. По много лесен начин, Bcrypt ви прави невъзможно някой да обрати процеса процеса на криптиране на паролата, дори и ако базата данни е компроментирана.

Имя няколко Bcrypt библиотеки за PHP, които може да ползвате.

Филтриране на данни

Никога, ама никога, не се доверявайте на потребителите и външния вход предоставен на вашият PHP код. Винаги филтрирайте и валидирайте входа преди да го използвате в кода си. Фунцкиите като filter_var и filter_input ви помагат да филтрирате и валидирате входа за основните типове формати (пр. email адрес, число или др.).

Външния вход може да бъде всичко: $_GET или $_POST данни от форма, някакви стойности в свръхглобалната променлива $_SERVER, както и тялото на HTTP заявка взето чрез: fopen('php://input', 'r'). Запомете външният вход не е ограничен до данни от форма пуснали от потребителя. Качените и свалени файлове, сесийни стойности, данни в бисквитките и външни данни от уеб услуги на трети страни също.

Когато външни данни са съхранени, комбинирани и достъпени по-късно, те все още са външен вход. Всеки път когато обработвате, извеждате, сбирате и включвате данни в кода си, попитайте се това: “Данните филтрирани ли са правилно и мога ли да им се доверя?”

Данните могат да се филтрират различно в зависимост от тяхното приложение. Например, когато нефилтрирани входни данни са подадени на изхода на HTML страница, това може да изпълни HTML и JavaScript във вашият сайт! Тази атака е още известна като Cross-Site Scripting (XSS) и не е маловажна, защото може да извлече много данни от потребителите без да знаят. Един начин за предотвратяване на XSS е да се филтрират всички HTML тагове от входа чрез премахването им или екранирането им.

Друг пример е предаването на опции за изпълнение в команден ред. Това може да е много опастно (и най-често е много лоша идея), но може да ползвате вдградената фунцкия escapeshellarg за екраниране на аргументите на командата.

Един последен пример e приемането на външен вход за определяне на файл за качване към файловата система. Това може да бъде експлоатирано, като се смени името на файла да бъде файлов път. Товага трбва да премахнете “/” или “../” или null байтове, или др. символи от името/пътя на файла за да не презапише скрити, непублични или други важни файлове.

Филтриране

Филтрирането на данните премахва (или екранира) невалидните и опасни символи от външния вход.

Например, вие трябва да филтрирате входа преди включването му в HTML или вкарването му в суров вид в SQL заявка. Ако ползвате обвързани параметри с PDO, то ще филтрира входа вместо вас.

Понякога е нужно да позволите някои безопастни HTML тагове във входа вкогато го включвате в HTML страница. Това обикновено е много трудоемко и често хората го избягват, като използват по-рестриктивни формати като Markdown или BBCode, въпреки че съществуват филтриращи библиотеки, като HTML Purifier поради тази причина.

Прочети повече за филтрите на данни

Валидация

Валидацията подсигурява,че външния вход е точно такъв вакъвто очаквате. Например, може да искате да валидирате email адрес, телефонен номер, дата на раждане като обработвате примерно регистрационна форма.

Прочети повече за валидаторите на данни

Конфигурационни файлове

Когато създавате конфигурационни файлове за вашите приложения, най-добрите практики препоръчват да се следва един от следните методи:

register_globals

NOTE: От версия PHP 5.4.0 register_globals настройката е премахната и не може да бъде ползвана. Извиква предупреждение при опит за ползването ѝ за да извести всеки, който в процес на обновяване на старо приложение.

Когато се включи настройката register_globals в конфигурацията, това прави няколко типа променливи (включващи такива от $_POST, $_GET и $_REQUEST) достъпни директно в глобалната област на видимост на приложението ви. Това може лесно да доведе до проблеми със сигурността, защото приложението не може еднозначно да определи от къде идват данните.

Например: Ако е дефинирана $_GET['foo'], тя ще бъде достъпна за приложението чрез $foo, което може само по себе си да презапише стойността на променлива която все още не е дефинирана.

Ако ползвате PHP < 5.4.0 задължитено изключете register_globals.

Докладване на грешки

Записването на грешките в лог файл може да бъде полезен начин за търсене на проблеми в вашето приложение, но също може да разкрие на външния свят информация за структурата на вашето приложение. За ефективна защита на приложението от проблеми свързани с извеждането на тези съобщения, вие трябва да конфигурирате сървъра различно в зависимост от средата на която се изпълнява приложението - т.е. развойна среда и реална среда.

Развойна среда - среда на разработка, докато приложението се разработва и тества все още (примерно - локалхост).

За да показвате грешките във вашата развойна среда, задайте следните настройки в php.ini:

Реална среда

За да скриете грешките в реална среда, настройте php.ini както следва:

С тези настройки за реална среда, грешките ще бъдат записвани в лог файла за грешки на сървъра и няма да бъдат показвани на потребителите. За повече информация, посъветвайте се с документацията на PHP:

Нагоре

Тестване

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

Има няколко типа инструменти (или рамки) за тестване на приложение за PHP, които ползват различни подходи, но всичките се опитват да избегнат ръчното тестване и нуждата от големи екипи за конрол на качеството (QA), само да за се подсигурят, че последните промени не са счупили вече съществуващата фунционалност.

Разработване основано на тестове (Test-driven Development)

От Уикипедия:

Разработване основано на тестове (TDD) е софтуерен процес за разработка, който разчита на повтарянето на кратки цикли на разработка: първо разработчика пише тест, който първоначално се проваля, който да тества желаната нова фунцкционалност, след това пише код за да мине теста и най-накрая преработва кода за да отговаря на стандартите. Kent Beck, който се смята че е разработил или ‘преоткрил’ техниката, през 2003 твърди, че TDD насърчава простите дизайни и дава увереност.

Има няколко различни типа тестване, които можат да помогнат за вашето приложение

Модулно тестване (Unit Testing)

Модулното тестване е техника при програмирането, която посигурвява функциите, класовете и методите да работят както се очаква през цялото време на цикъла на разработка. Посредством проверка на входни и изходни данни за различни функции и методи, можете да проверите дали вътрешната логика работи правилно. Използвайки шаблона “Внедряване на зависимости” (Dependency injection) и правенето на “mock” класове и пънчета (stubs), вие може да проверите дали тези зависимости са правилно ползвани за още по-добро покритието на теста (test coverage).

Когато създаваш клас или фунцкия първо трябва да създадеш тест за модул (unit test) за всяко едно поведение, което имаш. Най-основното е да подсигуриш, че хвърля грешка при подадени грешни аргументи (параметри) и да работи при подадени правилни аргументи. Това ще осигури, при промяна на класа или фунцкията в процеса на разработка, че няма да се счупи предишната функционалност. Единствената антернатива на модулното тестване е var_dump() в test.php, но това не е начин за направата на приложение, било то голямо или малко.

Тестовете намират приложение, когато допринасяте за отворен код. Ако напишете тест, който показва счупена функционалност и след това я оправите и теста да мине без грешки, пача (patch) най-вероятно ще бъде приет. Ако имате проект, които приема pull request - заявки, тогава трябва да предложите това като изискване.

PHPUnit е дефакто стандарт в рамките за тестване (testing frameworks) за писане на модулни тестове за PHP приложения, но има и няколко други алтернативи:

Интеграционно тестване (Integration Testing)

От Уикипедия:

Интеграционното тестване (понякога наричано Интегриране и Тестване, с абревиатура “I&T”) е фаза от софтуерното тестване, в която индивидуални софтуерни модули са комбинирани и тествани като група. Фазата на интеграционно тестване е след модулното тестване и преди тестването на валидация на приложението. Интеграционното тестване взима за вход вече тествани модули, събира ги в групи и прилага тестове определени от интеграционен план за тестване изкарвайки на изхода интегрирана система готова за системно тестване.

Много от интрументите могет да бъдат ползвани за модулно тестване могат да бъдат ползвани за интеграционно тестване, защото голяма част от принципите на раобта се препокриват.

Функционално тестване (Functional Testing)

Понякога се ползва термина тестване за приемане (acceptance testing), фунционалното тестване се състои в използването на инструменти за създаване на автоматизирани тестове, които ползват приложението вместо да верифицират отделни части от код дали работят правилно или това индивидуалните единици разговарят правилно. Тези инструменти обикновено се ползват с реални данни и симулират работата на реални потребители на приложнеието.

Инструменти за фунционално тестване

Разработване основано на поведение (Behavior Driven Development)

Има два типа разработване основано на поведение: SpecBDD и StoryBDD. SpecBDD се фокусира на техническото поведение или код, докато StoryBDD е насочено към бизнеса, чертите на поведение и взаимотношенията. PHP има рамки за двата типа РОП (BDD).

Със StoryBDD, вие пишете на човешки език истории които описват поведението на вашето приложение. Тези истории могат да пускат реални тестове на вашето приложение. Рамката използвана в PHP приложенията за StoryBDD е Behat, която е вдъхновена от Cucumber за Руби (Ruby), преоект който реализира Gherkin DSL (Domain-specific Language) за описване на чертите на поведение.

Със SpecBDD, вие пиешете спецификация как въщност вашият код трябва да се държи. Вместо да тествате функция или метод, вие описвате как трябва да се държи. За тази работа PHP предлага рамката PHPSpec. Тази рамка е вдъхновена от проекта RSpec project за Руби.

Инструменти за РОП (BDD)

Интрументи допълващи тестването

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

Интрументи

Нагоре

Сървъри и внедряване

PHP приложенията могат да бъдат внедрени и пуснати на реални уеб сървъри по много различни начини.

Платформата като услуга (Platform as a Service)

PaaS предлага системна и мрежова архитектура нужна да запуснеш PHP приложения в уеб пространството. Това означава малко или никаква настройка за стартирането на PHP приложение или PHP рамка.

Наскоро PaaS стана популярен метод за внедраване, хостване (hosting) и разширяване (scaling) на PHP приложения от всички размери. Можете да намерите списък с доставчиците на PHP PaaS “Platform as a Service” в нашата секция с ресурси.

Виртуални или наети сървъри

Ако сте наясно със системното администриране или се интересувате от изучаавнето му, виртуалните и наети сървъри ще ви предоставят пълен контрол над реалната средата за вашето приложение.

nginx и PHP-FPM

PHP се връзва много лесно и точно с nginx, чрез вградения за PHP’s FastCGI Process Manager (FPM), nginx е лек и бърз уеб сървър с висока производитленост. Той заема по-малко памет от Apache и обработва по-добре множество едновременни заявки. Това е много важно когато става дума за виртуални сървъри, които нямат много свободна памет (RAM).

Apache и PHP

PHP и Apache имат дълга история заедно. Apache има много настройки и много налични модули които разширяват фунционалността. Това е най-популярният избор за споделени сървъри и е лесен за настройване за работа с PHP рамки и приложения с отворен код като WordPress. За жалост, Apache, в общият случай, използва много повече ресурси от колкото nginx и не може да се справи с много посетители едновременно.

Apache има няколко възможни конфигурации за работа с PHP. Най-често ползваният подход е prefork MPM с mod_php5. Въпреки, че това не е най-ефективният по отношение на памет метод, това е най-простият начин да накараш PHP да тръгне. Това е вероятно най-добрият избор, ако не желаеш да се ровиш дълбоко в системната администрация. Забележка: Ако ползвате mod_php5 вие ТРЯБВА да ползвате prefork MPM.

В другият случай, ако искате максимална производителност и стабилност от Apache можете да се възползвате от същата FPM система, както nginx и да пуснете worker MPM или event MPM чрез mod_fastcgi или mod_fcgid. Тази конфигурация ще бъде значително по-екефтивна в работата си с памет и много по-бърза, но изисква време за настройката.

Споделени сървъри

PHP трябва да благодари за своята популярност на споделените сървъри. Трудно е да намериш хостинг без PHP, но проверявайте дали има поддържа за последната версия на PHP и на версиите на които искате вашето приложение да работи. Споделените сървъри позволяват на вас и на други разработчици да внедрят уеб сайтове/приложения на една машина. Положителната страна на това е, че е по евтино. Отрицателната в това, че не знаете вашите “съседи” какво могат да направят; основните опасения са в претоварването на сървъра или отварянето на дупка в сигурността. Ако бюджета на проекта ви го позволява, ползвайте нещо различно от спореден хостинг/сървър.

Нагоре

Кеширане (Caching)

PHP е достатъчно бърз сам по себе си, но се получават забавяния когато се правят отдалечени мрежови връзки, зареждане на файлове и др. За щастие, има техники и инструменти, които да забързат определени части от вашето приложение, или да намалят броят на извикванията на тежки процеси и задачи.

Кеширане на байткод

Когато един PHP файл се изпълнява, той бива предварително компилиран до байткод (bytecode), още известен като opcode в PHP. Чак тогава той бива изпълнен от процесора. Ако един PHP файл не е променян, то и неговият байткод не се променя. Това означава, че не харчат ненужни ресури за компилирането на скрипта отново и отново преди изпълнение.

За да отстрани този проблем, се намесва байткод кеширането. То премахва повторното компилиране, като съхранява байткода изцяло в паметта и го преизползва в последвалите извиквания. Настройката на кеширането на байткод отнема минути, а приложението се забързва в пъти. Няма причина да не го ползвате.

Известни разширения за кеширане на байткод:

Кеширане на обекти

Има моменти, когато е важно да кеширате индивидуални обекти в вашият код, например когато достъпването на данните от базата данни е бавна операция, а резултатът рядко се променя. Можете да ползвате обекно кеширане в този случай, за да запазвате данните в паметта за изключително бърз достъп. Ако съхраните данните в хранилище за данни (кеш) след като ги извлечете от базата данни и в последващите заявки ги извличате от кеша, ще получите значително подобрение в производителността, както и ще намалите натоварването на база данни сървърите.

Много от популярните решения за кеширане на байткод, също предоставят механизми за съхранение на данни, от което може да се възползвате. APC, XCache и WinCache предоставят API-и за съхранение на данни в тяхната памет директно от вашият PHP код.

Най-често ползваните системи за обектно кеширане са APC и memcached. APC е един отличен избор за обектно кеширане, защото включва просто API за добавяне на ваши данни в кеш паметта и е много просто за настройка и ползване. Основен проблем на APC е това, че е обвързан със срвъра на който е инсталиран. От друга страна, memcached е инсталиран като отделна услуга и може да бъде достъпван през мрежата, което означава, че може да запазвате обекти в много бързо хранилище за данни, намиращи се на централно място, и много системи могат да извличат данни от него.

При проста мрежова конфигурация APC обикновено е по-бърз от memcached, но memcached може да се разширява по-бързо и повече. Ако не смятате, че вашето приложение трябва да работи на повече от един сървър, нямате нужда от допълнителните възможности на memcached и вероятно APC е най-добрият избор за кеширане на обекти.

Опростен пример и логика чрез APC:

<?php
// Проверяваме дали има данни с име 'expensive_data' в кеша
if (apc_fetch('expensive_data') === false) {
    // данните не са в кеша; изпълни скъпо извикване и съхрани за последващо използване
    apc_add('expensive_data', get_expensive_data());
}

print_r(apc_fetch('expensive_data'));

НАучете повече за по-известните системи за кеширане на обекти:

Нагоре

Ресурси

От източника

Хора да “следваш” в Туитър

Менторство

PHP доставчици на PaaS услуги

Рамки - фреймуоркс

Вместо да преоткриват колелото, много PHP разработчици използват т.нар. рамки за разработка на техните приложения. Рамките премахват проблема с грижата за нещата от ниско ниво, като предоставят готова “рамка”, структура и предоставят лесен и полезен интерфейс за често срещаните задачи.

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

Микрорамките обикновено просто обвиват HTTP заявките и ги насочват към фунцкия, контролер, метод и др. и понякога включват няколко библиотеки, които да помогнат с разработватването, например прост слой за компуникация с базата данни. В момента, най-често се ползват при разработката на отдалечени HTTP услуги (Web Services).

Много рамки добавят много повече възможности в сравнение с микрорамките, тези рамки са известни като пълни рамки (Full-Stack Framework). Обикновено идват в пакет с ORM, пакети за автентикация и др.

Компоентните рамки за колекции от специализирани библиотеки, всяка от които едно точно приложение. Отделни части от рамките от компоненти могат да бъдат ползвани за направата на микрорамки или пълни рамки.

Компоненти

Както споменахме преди, “компонентите” са друг подход към общата цел за съдаването, разпространението и разработката и преизползването на споделен код. Има много различни хранилища за компоненти. Две от основните са:

И двете хранилища разполагат с инструменти за инсталиране, обновяване на компоненти. Това е обяснено по-добре и в детайли в секцията Управление на зависимости.

Има компонентни рамки, които ви позволяват да индивидуално техните компоненти с минимални или никакви допълнителни изисквания. Например, можете да ползвате пакета FuelPHP Validation, без да е необходимо да ползвате цялата рамка FuelPHP. Тези проекти същност да просто едино хранилище от компоненти за преизползване:

Нагоре

Общност

The PHP community is as diverse as it is large, and it’s members are ready and willing to support new PHP programmers. You should consider joining your local PHP user group (PUG) or attending larger PHP conferences to learn more about the best practices shown here. You can also hang out on IRC in the #phpc channel on irc.freenode.com and follow the @phpc twitter account. Get out there, meet new developers, learn new topics and, above all, make new friends.

Прочети календара с официални събития на PHP

PHP групи от потребители

Ако живееш в голям град, много е вероятно да има PHP група наоколо. Въпреки че няма официален списък от PUGs (PHP User Groups), можете ленсо да намерите локална PUG като потърсите в Google или Meetup.com. Ако живеете в по-малък град, вероятно няма да има локална PUG; в такъв случай, направете една!

Прочети относно потребителските групи в PHP Wiki

PHP конференции

PHP общността е също домакин на големи регионални и национални конференции в много страни по света. Добре известни членове на PHP общността обикновено говорят на тези събития, което е възможност да научиш нещо ново директно от големите в PHP.

Намери PHP конференция