Рекомендации по написанию кода
Здравствуйте, уважаемые пользователи Pro-Pawn.ru.
Многие новички не могут разобраться в основах скриптинга потому, что не осознают самых элементарных правил не только скриптинга, но и программирования в целом.
Обычно люди сами выбирают свой стиль кодинга, но согласитесь, будет гораздо проще писать весь свой код по одному стандарту, чем работать без оного с кашей из разных стилей. Да и не стоит забывать, что код, который вы выкладываете на Pro-Pawn, кроме вас будет использоваться другими скриптерами.
Поэтому я собрал самые распространённые правила в один стиль кодинга на Pawn.
Итак, начнём:
- Глобальные переменные следует называть длинными именами.
Не используйте слишком короткие и простые имена для глобальных переменных, т.к. такие имена часто могут использоваться для локальных переменных.
Пример плохого кода:
PHP код:
new Float:x, Float:y, Float:z; // координаты спавна (глобальные переменные)
stock SetSpawnPos()
{
x = 0.0, y = 1.0, z = 2.0; // здесь эти глоб. переменные используются
}
stock PrintPos(playerid)
{
new Float:x, Float:y, Float:z; // а здесь компилятор выдаст предупреждение,
// т.к. переменные "x", "y" и "z" уже были объявлены
// в качестве глобальных переменных
GetPlayerPos(playerid, x, y, z);
printf("%.4f, %.4f, %.4f", x, y, z);
}
Как видно, в данном примере внутри функции PrintPos создаются локальные переменные x, y и z, но эти имена уже заняты. Происходит коллизия имён - конфликт между переменными/функциями/константами с одинаковыми названиями.
Вывод: если создаёте глобальные переменные, задавайте им достаточно длинные и осмысленные названия, чтобы не было конфликтов имён с локальными переменными.
Уточним названия переменных: добавим слово "spawn", чтобы было понятно, что это координаты спавна.
Пример хорошего кода:
PHP код:
new Float:spawn_x, Float:spawn_y, Float:spawn_z; // координаты спавна (глобальные переменные)
stock SetSpawnPos()
{
spawn_x = 0.0, spawn_y = 1.0, spawn_z = 2.0; // здесь эти глоб. переменные используются
}
stock PrintPos(playerid)
{
new Float:x, Float:y, Float:z; // ok (имена "x", "y" и "z" не заняты глобальными переменными)
GetPlayerPos(playerid, x, y, z);
printf("%.4f, %.4f, %.4f", x, y, z);
}
Теперь локальные переменные больше не будут конфликтовать с глобальными, т.к. мы добавили к названиям глобальных переменных префикс "spawn_". Этот префикс выбран потому, что в переменных сохраняются координаты спавна (ваш Кэп). Таким образом удалось избежать коллизии имён.
- Не стоит писать названия переменных, констант и функций на транслите. Это должно быть очевидно, как убого выглядит код, написанный на транслите или на ломанном английском.
Если же у вас проблемы с иностранными языками - учите английский. Либо завязывайте со скриптингом, потому что знание английского - неотъемлимая часть в обучении программированию.
- Придерживайтесь одного и того же стиля задания имён для переменных, констант и функций.
Ниже описан самый распространённый стиль среди сообщества SA:MP:- Имена констант пишутся большими буквами, слова в названии разделяются знаком подчёркивания (_).
- Названия переменных рекомендуется писать маленькими буквами, слова так же разделяются символом подчёркивания.
- В именах функций каждое слово пишется с большой буквы, при этом слова не разделяются никакими знаками.
- Часть имени переменной может писаться большими буквами, если это сокращение (например, "HTTP_response_code", "forum_URL", "TD_health"). То же самое исключение относится и к именам функций ("HTTPCallback", "OpenURL").
Пример:
PHP код:
// переменная
new logged_players_count;
// константа
const MAX_HOUSES = 256; // либо #define MAX_HOUSES 256
// функция
stock GetMaxHouses()
{
return MAX_HOUSES;
}
Делается это для того, чтобы потом по имени можно было легко понять, константа ли это, переменная или функция.
Примечание: в SA:MP также есть функции "db_open", "tickcount", "printf", и т.д., но все они - всего лишь отголоски тех времён, когда никто особо не задумывался о стандартах. Все писали код по-своему, отсюда и путаница.
Потому логично считать те функции не правилом, а исключением из правил.
- Названия глобальных переменных, констант и функций должны говорить об их назначении.
Плохой пример:
PHP код:
Textdraw0, Textdraw1, Textdraw2, ...
Из названия этих переменных понятно только то, что это текстдравы, а что это за текстдравы и для чего они предназначены - гадайте сами! Больше никакого смысла в этих названиях нет.
Придётся лишний раз выискивать все места, где используются эти переменные, чтобы понять, для чего они нужны.
Хороший пример:
Здесь сразу становится ясно, что это текстдрав логотипа сервера. При этом префикс "TD" указывает на то, что в переменной хранится ID текстдрава.
Использование префиксов и постфиксов в переменных и константах не обязательно, но всё же рекомендуется, т.к. с ними значительно легче определить тип переменной и область видимости: не нужно смотреть место, где объявлена переменная/константа, достаточно лишь посмотреть на её название.
Список часто используемых префиксов:- "DLG" для констант с номерами диалогов.
- "obj" для переменных под ID объектов.
- "pobj" для объектов, создающихся для отдельных игроков (функцией CreatePlayerObject).
- "TD" для текстдравов (большими буквами потому, что в сокращение попадают только большие буквы из "TextDraw").
- "PTD" для текстдравов, создающихся для отдельных игроков (PlayerText).
- Старайтесь правильно табулировать код (или, как это ещё называют, писать код лесенкой).
Избегайте каши из пробелов вперемешку с табами - её трудно заметить в редакторе кода, но на форуме из-за такой каши часто становятся заметны проблемы с табуляцией.
Желательно табулировать код только с помощью Tab, т.к. во многих редакторах кода можно настроить под свой вкус их ширину (т.е. 1 таб можно сделать равным 3 пробелам вместо 4), чего нельзя сделать с пробелами. Кроме того, при неправильной табуляции лишний таб заметить намного легче, чем пробел.
Отыскивать лишние пробелы удобнее всего в Notepad++ с включенным отображением невидимых символов.
Помните: правильно оттабулированный код - залог понимания другими скриптерами.
- Не пытайтесь записывать весь код в одну строку - компилятору нет дела до стиля оформления исходного кода, результат в AMX будет один и тот же.
Зато таким "утрамбовыванием" вы можете здорово испортить читаемость кода для себя и других скриптеров.
Пример плохого кода (взято прямиком из ада из RLS):
PHP код:
if (strcmp(cmd,"/stuff",true)==0){new string[32];
format(string,sizeof(string),"Ваш уровень: %d",GetPlayerScore(playerid));SendClientMessage(playerid,-1,string);return 1;}
Исправим ситуацию:
PHP код:
if (strcmp(cmd, "/stuff", true) == 0)
{
new string[32];
format(string, sizeof(string), "Ваш уровень: %d", GetPlayerScore(playerid));
SendClientMessage(playerid, -1, string);
return 1;
}
Примечание: на самом деле утрамбовывание строк может привести к уменьшению файла .amx, но это только из-за отладочной информации. Чем больше строк в исходном коде, тем больше весит отладочная информация (~2 байта на строку, результат может варьироваться из-за сжатия содержимого AMX), но на характеристиках выполнения скрипта это никак не сказывается. Если вы хотите, чтобы ваш скрипт меньше весил и сервер тратил меньше памяти при выполнении скрипта, есть смысл вообще убрать всю отладочную информацию - для этого в папке с компилятором (pawncc) создайте файл pawn.cfg и пропишите в нём "-d0".
- Избегайте использования "магических чисел", которые никто, кроме вас, объяснить не может.
Плохой пример:
PHP код:
new some_array[10];
public OnGameModeInit()
{
for (new i = 0; i < 10; i++)
some_array[i] = random(2);
}
CMD:printarr(playerid, params[])
{
for (new i = 0; i < 10; i++)
printf("%d", some_array[i]);
}
Почему пример плохой? Хотя бы потому, что не сразу понятно, откуда взялось число 10 в условии выхода из цикла.
Кроме того, попробуйте поменять размер массива - придётся перерывать весь мод, выискивая каждый цикл, работающий с тем массивом, чтобы заменить размер на новый. Многие начинающие скриптеры именно так и забывают сменить размер в циклах, после чего в работе сервера часто возникают ошибки из-за выхода за пределы массива (привет RLS-никам!)
Хороший пример:
PHP код:
new some_array[10];
public OnGameModeInit()
{
for (new i = 0; i < sizeof(some_array); i++)
some_array[i] = random(2);
}
CMD:printarr(playerid, params[])
{
for (new i = 0; i < sizeof(some_array); i++)
printf("%d", some_array[i]);
}
Теперь достаточно лишь один раз сменить размер массива в месте его объявления, остальную работу компилятор возьмёт на себя. Такой код будет куда более надёжным.
Ещё пример:
PHP код:
const SOME_ARRAY_SIZE = 10;
new some_array[SOME_ARRAY_SIZE];
public OnGameModeInit()
{
for (new i = 0; i < SOME_ARRAY_SIZE; i++)
some_array[i] = random(2);
}
CMD:printarr(playerid, params[])
{
for (new i = 0; i < SOME_ARRAY_SIZE; i++)
printf("%d", some_array[i]);
}
Здесь размер массива определяется константой, что тоже приемлемо в некоторых ситуациях. Например, во многих системах домов есть константа "MAX_HOUSES" и было бы удобнее использовать её вместо "sizeof(house_info)".
- Используйте константы при каждой возможности.
Плохой пример:
PHP код:
public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
if (newkeys == 327808)
{
// ...
}
}
А теперь вопрос: почему же пример плохой?- В новых версиях сервера SA:MP значения констант могут измениться. Константы SA:MP сделали разработчики мультиплеера, они же имеют право и изменить их в следующих версиях, если это будет нужно.
В этом случае, если вы используете числа вместо констант, вам придётся перешаривать весь мод, вручную выискивать все нужные числа (среди over 9000 других чисел) и заменять их.
Да, в стагнирующем проекте типа SA-MP такие изменения маловероятны, но это ещё не отменяет их возможности. Использование "магических чисел" вместо констант считается плохой практикой.
- Для того, чтобы понять, какие клавиши проверяются в примере, придётся смотреть таблицу (либо постоянно держать эти числа в голове), вместо того, чтобы просто прочитать их названия на английском языке и сразу всё понять. Если же у вас проблемы с иностранным языком - см. пункт 2.
Хороший пример:
PHP код:
public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
if (newkeys == KEY_AIM | KEY_YES | KEY_CTRL_BACK)
{
// ...
}
}
В этом примере названия клавиш уже расписаны на английском языке и не составит никакого труда понять их.
Ещё пример:
PHP код:
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
switch (dialogid)
{
case 0:
return 1;
case 1:
{
if ((inputtext[0] != '\0') && (0 == strcmp(inputtext, player_info[playerid][pPassword])))
player_login_status{playerid} = true;
return 1;
}
case 2:
{
// ...
}
// ...
}
return 0;
}
Чтобы правильно составлять диалоги и обработку пользовательского ввода в них, придётся либо заучивать ID всех диалогов наизусть (а их в моде может накопиться под несколько сотен), либо каждый раз перед использованием ShowPlayerDialog заглядывать в OnDialogResponse и выискивать там нужный ID. В любом случае это лишняя работа для скриптера.
А теперь представим такую ситуацию: в моде 100 разных диалогов и вдруг понадобилось удалить диалог под номером 50 - вы не сможете просто так взять и поставить диалог #51 на место #50, #52 на место #51 и т.д. Вам придётся либо потратить уйму времени на перестановки, либо оставить 50-й ID диалога неиспользованным.
Решение: использовать именованные константы для ID всех диалогов.
PHP код:
enum
{
// Компилятор сам распределит значения: константа DIALOG_ID_NONE будет равна нулю, DIALOG_ID_LOGIN - 1, DIALOG_ID_REGISTER - 2 и т.д.
// Если захотите удалить DIALOG_ID_LOGIN, то DIALOG_ID_REGISTER вместо 2 станет равна 1
// и значения всех последующих констант тоже уменьшатся на единицу.
DIALOG_ID_NONE,
DIALOG_ID_LOGIN,
DIALOG_ID_REGISTER,
// ...
};
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
switch (dialogid)
{
case DIALOG_ID_NONE:
return 1;
case DIALOG_ID_LOGIN:
{
if ((inputtext[0] != '\0') && (0 == strcmp(inputtext, player_info[playerid][pPassword])))
player_login_status{playerid} = true;
return 1;
}
case DIALOG_ID_REGISTER:
{
// ...
}
// ...
}
return 0;
}
- Константы, обозначающие неправильный порядковый номер (ID) или количество чего-либо, должны быть равны -1.
Рассмотрим это правило на примере константы, означающей, что у игрока нет дома.
Плохой пример:
PHP код:
const MAX_HOUSES = 100; // На сервере всего 100 домов.
const INVALID_HOUSE_ID = 255; // Если в player_info[playerid][pHouseKey] число 255, то у игрока нет дома.
// Почему бы и нет, ведь у меня на сервере только дома с ID от 0 до 254?
Но что будет, если вы потом захотите создать больше 255 домов? Сделаете 255-й дом на координатах, куда не сможет пробраться обычный игрок (например, под землёй)? Это уже костыль. Решается же эта проблема очень просто.
Хороший пример:
PHP код:
const MAX_HOUSES = 300;
const INVALID_HOUSE_ID = -1; // Число -1 не будет конфликтовать с макс. кол-вом домов, т.к. число домов не может быть отрицательным.
Похожая проблема была в моде GodFather (интересно, кто-нибудь из "нынешнего поколения" видел этот мод?): там число 255 использовали как неправильный ID игрока. Потом вышел SA-MP 0.3a, в котором к серверу могли подключиться до 500 игроков - тогда 255 перестал быть неправильным ID, что приводило к багам и весьма неожиданным последствиям для тех, кому не повезло зайти под 255-м ID.
- Не путайте целые числа с вещественными.
Пример плохого кода:
PHP код:
new Float:some_float = 10;
new some_float_sqr = floatpower(some_float, 2);
new Float:health;
GetPlayerHealth(playerid, health);
SetPlayerHealth(playerid, health + 10);
Казалось бы, ничего особенного. Но давайте посмотрим, во что компилятор превращает этот код:
PHP код:
new Float:some_float = float(10);
new some_float_sqr = floatpower(some_float, float(2));
new Float:health;
GetPlayerHealth(playerid, health);
SetPlayerHealth(playerid, health + float(10));
Видите эти лишние вызовы функции float()? Компилятор подставляет их, если вы используете целые числа там, где нужно использовать вещественные.
Это не смертельно, но может увеличить нагрузку на сервер, ведь он будет тратить лишнее время на то, чтобы преобразовать число из целочисленного формата в число с плавающей запятой (Float) - просто потому, что кто-то поленился дописать ".0" в конце числа.
Пример хорошего кода:
PHP код:
new Float:some_float = 10.0;
some_float += 2.0;
new some_float_sqr = floatpower(some_float, 2.0);
new Float:health;
GetPlayerHealth(playerid, health);
SetPlayerHealth(playerid, health + 10.0);
Как видите, достаточно просто добавить ".0" к числам, чтобы сделать их вещественными. Это не трудно.
Главное только, наоборот, не указывать вещественные числа там, где нужны целые, иначе это может привести к ошибкам.
- Старайтесь, чтобы ваш код укладывался в лимит: 80 символов на строку. Если не вмещается - переносите.
В коде будет больше строк, но зато вам не придётся лишний раз тянуться к полосе горизонтальной прокрутки в редакторе кода, чтобы посмотреть на то, что не влезает на экран.
Обычно лимит в 80 символов выделяется линией в pawno, SynWrite и многих других редакторах кода, аналогично полям в школьных тетрадях.
Пример плохого кода:
PHP код:
SetObjectMaterialText(objectid, "Sample text", 0, OBJECT_MATERIAL_SIZE_512x512, "Arial", 12, 1, 0x00000000, 0xFFFFFFFF, OBJECT_MATERIAL_TEXT_ALIGN_CENTER); //155
Строка кода занимает 155 символов, придётся тянуться за полосой горизонтальной прокрутки в редакторе, чтобы увидеть последние параметры.
Исправим ситуацию, перенеся параметры функции на новые строки:
PHP код:
SetObjectMaterialText(
objectid, "Sample text", 0, OBJECT_MATERIAL_SIZE_512x512,
"Arial", 12, 1, 0x00000000, 0xFFFFFFFF, OBJECT_MATERIAL_TEXT_ALIGN_CENTER //77 симв.
);
Цель достигнута: самая длинная строка кода занимает 77 символов, что укладывается в лимит <=80.
Ещё пример:
PHP код:
CreateObject(404, 1138.000, 146.0000, 0.0000, 0.0000, 0.0000, 128.0000, 500.0000); //82
Исправляем, сгруппировав координаты и углы поворота:
PHP код:
CreateObject(
404,
1138.000, 146.0000, 0.0000, //31 символ
0.0000, 0.0000, 128.0000,
500.0000
);
Или даже так, сэкономив пространство по вертикали:
PHP код:
CreateObject(
404, 1138.000, 146.0000, 0.0000, 0.0000, 0.0000, 128.0000, 500.0000); // 73
И ещё один пример:
PHP код:
format(buffer, sizeof(buffer), "Имя: %s\nУровень: %d\nДеньги: %d$\nАдрес: %s, %d\nОрганизация: %s\n", player_name, level, money, player_city, player_house_id, player_family_name); //179
Переносим параметры:
PHP код:
format(
buffer, sizeof(buffer),
"Имя: %s\n"\
"Уровень: %d\n"\
"Деньги: %d$\n"\
"Адрес: %s, %d\n"\
"Организация: %s",
player_name, level, money, player_city, // 43
player_house_id, player_family_name
);
Обратите внимание: строковое значение разбито на несколько строк. Также их уровень табуляции увеличен на 1, чтобы показать, что это одна строка, а не 5 разных строк.
- Тело циклов for, do и while (если они не пустые) и ветвления if следует переносить на отдельную строку для лучшей читаемости.
Плохой пример:
PHP код:
if (0 == IsPlayerAdmin(playerid)) return SendClientMessage(playerid, -1, "Ошибка: Вы не администратор!");
Хороший пример:
PHP код:
if (0 == IsPlayerAdmin(playerid))
return SendClientMessage(playerid, -1, "Ошибка: Вы не администратор!");
- Аббревиатуры в названиях должны записываться в верхнем регистре.
Примеры:
PHP код:
// HTTP - HyperText Transfer Protocol
native HTTP(index, type, url[], data[], callback[]);
// NPC - Non-Player Character
native ConnectNPC(name[], script[]);
forward OnNPCSpawn();
// EOF - End Of File
const EOF = -1;
- Для функций, выполняющих проверку чего-либо, следует использовать префикс Is.
Примеры:
Код:
// из стандартных функций SA:MP
native IsObjectMoving(playerid);
native IsPlayerConnected(playerid);
native IsPlayerInAnyVehicle(playerid);
// примеры пользовательских функций
stock bool:IsHouseUnoccupied(houseid);
stock IsRPNick(name[]); // Название кликабельно.
- Префиксы Get/Set должны использоваться в названиях функций, которые получают или изменяют (устанавливают) значение какого-либо атрибута.
Таким атрибутом может быть здоровье игрока, его уровень, игровое время на сервере - что угодно, к чему нельзя получить доступ из скрипта напрямую, как к переменной, но можно получить/изменить с помощью функции.
Примеры:
Код:
// из стандартных функций SA:MP
native GetPlayerPos(playerid, &Float:x, &Float:y, &Float:z);
native SetPlayerPos(playerid, Float:x, Float:y, Float:z);
native GetVehicleHealth(vehicleid, &Float:health);
native SetVehicleHealth(vehicleid, Float:health);
native SetGravity(Float:gravity);
native SetWeather(weatherid);
// примеры пользовательских функций
stock GetHouseValue(houseid);
stock SetHouseValue(houseid, price);
stock GetBusinessFee(businessid);
stock SetBusinessFee(businessid, fee);
- Массивы, у которых в ячейках сохраняются только значения от 0 до 255, следует объявлять с указанием слова char в размере, чтобы сэкономить кол-во отводящейся под массив памяти, используя под ячейку всего 1 байт вместо 4.
Доступ к ячейкам таких массивов должен осуществляться с помощью фигурных скобок ({}) вместо квадратных ([]).
Пример:
PHP код:
new player_login_status[MAX_PLAYERS char];
#define IsPlayerLoggedIn(%0) (player_login_status{%0})
public OnPlayerConnect(playerid)
{
player_login_status{playerid} = 0;
// ...
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
if (dialogid == DIALOG_ID_LOGIN)
{
player_login_status{playerid} = 1;
// ...
}
// ...
}
CMD:do(playerid, params[])
{
if (0 == IsPlayerLoggedIn(playerid))
return SendClientMessage(playerid, -1, "Ошибка: Вы не залогинены!");
// ...
}
- Инклуды (.inc) должны содержать защиту от повторного подключения (include guard).
Раньше этот метод защиты был совершенно не нужен, поскольку сам компилятор Pawn не позволял подключить один и тот же файл дважды.
Однако эта возможность работала не на всех платформах (некорректная работа в Linux и OS X), из-за чего скрипты, компилировавшиеся под Windows могли не скомпилироваться под OS X.
В новой версии компилятора от Zeex данная возможность убрана, чтобы компилятор одинаково работал на всех платформах.
Поэтому теперь есть смысл самостоятельно защищать свои файлы от повторного использования.
Пример:
PHP код:
// файл: my_functions.inc
#if defined MY_FUNCTIONS_INC // если файл уже был подключен ранее -
#endinput // прервать дальнейшую обработку файла
#endif
#define MY_FUNCTIONS_INC // объявить макрос, чтобы компилятор в следующий раз
// "знал" о том, что этот файл уже был подключен
// ваш код
#include <a_samp>
//...
- Переменные, находящиеся внутри инклуда, должны быть доступны только внутри него с помощью атрибута static.
Если же нужно получить/изменить значение такой переменной извне, можно сделать для этого отдельные функции:
Пример:
PHP код:
// файл: jetpack.inc
static stock player_has_a_jetpack[MAX_PLAYERS char];
stock IsPlayerInAJetpack(playerid)
return player_has_a_jetpack{playerid};
- В инклудах должна быть возможность настройки и задания параметров из скрипта, в котором инклуд подключается.
Рассмотрим это на примере простого античита, который через заданный интервал времени проверяет, есть ли у игроков запрещённое оружие (пулемёт или гранатомёт, например), и при его наличии банит.
Античит через заданный интервал времени производит проверку всех игроков на наличие запрещённого оружия. Время проверки настраивается с помощью макроса MY_ANTICHEAT_CHECK_INTERVAL (2000 мс по умолчанию).
Плохой пример:
PHP код:
// файл: my_anticheat.inc
// Нужны более частые проверки - отредактируйте инклуд.
// Если выйдет новая версия инклуда - редактируйте заново.
#define MY_ANTICHEAT_CHECK_INTERVAL 2000
// ...
Редактирование настроек внутри инклуда - очень грязный вариант. Во-первых, сам по себе инклуд является зоной ответственности автора инклуда, а не пользователя. Во-вторых, при выходе обновления инклуда пользователю придётся заново редактировать файл, чтобы восстановить прежние настройки - и так с каждой новой версией (особенно "приятно" вспоминать, какие настройки были выставлены в предыдущей версии, если бросил новую версию инклуда в папку "includes" с заменой старой версии, а из старой забыл заранее скопировать настройки).
Хороший пример:
PHP код:
// файл: mode.pwn
#define MY_ANTICHEAT_CHECK_INTERVAL 500 // Перед тем, как подключить инклуд с античитом, задаём интервал проверки.
#include "my_anticheat.inc" // Подключаем инклуд (проверка будет выполняться примерно через каждые 500 мс).
PHP код:
// файл: my_anticheat.inc
#if !defined MY_ANTICHEAT_CHECK_INTERVAL // Если интервал не был задан в скрипте перед подключением инклуда...
#define MY_ANTICHEAT_CHECK_INTERVAL 2000 // ... устанавливаем время по умолчанию
#endif
Как видите, в инклуд потребовалось добавить всего пару строк. Это не так уж и сложно.
Теперь чтобы изменить те или иные настройки, пользователю не придётся лезть в сам инклуд.
По такому же принципу оформлены настройки в YSI (например, _YSI_NO_VERSION_CHECK отключает проверку обновлений YSI при каждой загрузке скрипта) и других профессионально реализованных инклудах. Кроме того, аналогичная практика используется во многих фреймворках и библиотеках на C/C++.
В дальнейшем содержимое темы будет исправляться и дополняться.
P.S.:
Цитата:
Сообщение от
Seregamil
кому как удобно пусть так и оформляют
Стрельба себе в ногу - дело добровольное. Я никому этого не запрещаю.
Автор: Daniel_Cortez
Копирование данной статьи на других ресурсах без разрешения автора запрещено!