Напоследък помагам на един приятел да разбере някакъв код и как да го промени, за да работи добре с асинхронни заявки към бекенда. Бонус би било да може да се напише по-модулно и преизползваемо.
Кодът е WordPress плъгин, написан с много наследен (legacy) подход – бизнес и фронтенд логиката са смесени на едно място. Манипулации на данни, правени по средата на шаблонния код и подобни неща.
Всъщност това е горе-долу онова, което сте виждали в PHP сайтовете от началото на 2000-те, преди всички страхотни ООП допълнения към езика и купчината зрели фреймуърци.
Случаят, по който работих днес, беше следният – имаш таблица, която показва куп записи. Трябваше да добавим няколко филтъра към таблицата и да я накараме да работи през AJAX, за да се обновява бързо интерфейсът, без да се презарежда цялата страница на WordPress Admin.
Филтрирането на данните беше лесно – един бърз inline array_filter, който да филтрира данните, преди да бъдат подадени към шаблонния код (за да запазим същия стил на кода, и това беше в шаблонния файл 😇).
Проблемът дойде, когато започнахме да работим по това таблицата да може да се рендерира през AJAX.
Тя е по средата на куп друг шаблонен и бизнес код. Ако искахме през AJAX да връщаме само таблицата, имахме съвсем малко начини да го постигнем.
Първият начин би бил да обвием HTML-а преди и след таблицата в ОГРОМНИ if конструкции, за да сме сигурни, че той не се рендерира.
Друг начин би бил да извадим шаблона в отделен файл и да го включим в AJAX action-а, който бихме дефинирали в кода на плъгина.
Анонимните функции на помощ!
Мислейки как да се справя с това по най-лесния възможен начин, опитах да дефинирам нормална PHP функция, която да съдържа кода на таблицата, но имаше проблем.
Кодът се изпълнява в метод на клас. В шаблона на таблицата има препратки към $this. Ако не искаме да променяме кода много, трябва да подадем $this като аргумент на функцията. Е, това не работи, защото не можеш да подадеш $this като параметър 🤷♂️.
Бях малко разочарован, че ще трябва да пренапишем доста неща в шаблона, а имаше доста препратки, за които трябваше да внимаваме, за да продължи всичко да работи.
Тогава си спомних, че сайтът не работи на PHP 5.2, а на PHP 7, така че анонимните функции се поддържат.
А те имат полезна възможност да определиш кои променливи от извикващия обхват да бъдат подадени на функцията, когато тя бъде извикана. Например:
$table_function = function() use ( $pages, $current_page, $items ) {
// ... Table render code
}Това ще ти позволи директно да използваш $pages или $items в тялото на функцията.
Страхотното тук е, че можеш да подадеш и $this като променлива в обхвата на функцията!
Така успяхме напълно да извадим кода за рендериране на таблицата в отделна функция, която можем да извикаме изолирано по време на AJAX заявката!
Разбира се, човек трябва да внимава много с променливите, използвани в тялото на функцията, защото те трябва да са дефинирани, така че внимавай откъде може да бъде извикана AJAX функцията.
За нас това означава, че ще добавим малък action в основния клас, който пак ще include-ва файла, но ще имаме повече контрол върху спирането на всички останали изходи, които иначе ще се случат.