Файл jsmin.php в Cotonti CMF
Файл jsmin.php в Cotonti CMF реализует PHP-версию библиотеки для минификации JavaScript-кода, которая является портом известного инструмента jsmin.c от Douglas Crockford, адаптированного для PHP. Этот файл служит для сжатия и оптимизации JavaScript-кода, удаляя ненужные пробелы, комментарии и другие избыточности, улучшая таким образом производительность веб-приложений, снижая время загрузки и ускоряя выполнение JavaScript в браузере.
Основное назначение:
Цель данного файла — минимизация (минификация) JavaScript-кода. Это процесс удаления лишних пробелов, комментариев, строк, не влияющих на работу программы, с целью уменьшения объема кода и ускорения его загрузки и выполнения в браузере. Этот процесс играет важную роль в веб-разработке, особенно для крупных проектов с большим количеством JavaScript-кода.
Место в системе Cotonti:
Файл находится в каталоге /lib/, что означает, что он представляет собой вспомогательную библиотеку, которая используется для минификации файлов JavaScript перед их отправкой в браузер клиента. Он может быть использован в рамках обработки и оптимизации файлов на серверной стороне перед их выводом пользователю или сохранением для дальнейшего использования.
Методы, функции и классы:
-
Класс
JSMin: КлассJSMinявляется основным элементом, который инкапсулирует логику минификации. Он содержит все необходимые функции для обработки и сжатия JavaScript-кода. Основной метод — этоmin(), который выполняет процесс минификации, принимая исходный JavaScript-код в виде строки и возвращая его оптимизированную версию. -
Метод
minify(): Это публичный статический метод, который инициализирует объект классаJSMinс переданным JavaScript-кодом и вызывает методmin()для выполнения минификации. Результат возвращается как сжатая версия исходного кода. -
Методы работы с символами и строками:
get(): Извлекает следующий символ из строки, обрабатывая специальные случаи, такие как замена символа возврата каретки на новую строку и игнорирование символов, которые не важны для минификации.next(): Обрабатывает комментарии (как однострочные, так и многострочные), и, если встречается комментарий, игнорирует его, возвращая следующий значимый символ.peek(): Используется для просмотра следующего символа без его извлечения, что полезно для обработки комментариев и регулярных выражений.action(): Основной метод, который выполняет разные действия в зависимости от текущего состояния и символов в потоке. В нем реализована логика обработки пробелов, новых строк, строковых литералов и регулярных выражений.isAlphaNum(): Проверяет, является ли символ буквой, цифрой, подчеркиванием или символом доллара. Это необходимо для правильной обработки идентификаторов и переменных в JavaScript.
-
Обработка ошибок: Для обработки ошибок используется класс
JSMinException, который наследует стандартный класс исключений PHP. Это позволяет генерировать и ловить исключения в случае возникновения ошибок, таких как незавершенные строковые литералы или регулярные выражения.
Суть содержания кода:
Код включает несколько ключевых этапов для выполнения минификации:
- Чтение и обработка символов: Код обрабатывает входной JavaScript, анализируя его символы по одному, игнорируя лишние пробелы, символы новой строки и комментарии.
- Обработка строк и регулярных выражений: Строковые литералы и регулярные выражения обрабатываются отдельно, чтобы избежать их случайного удаления в процессе минификации.
- Удаление ненужных пробелов и комментариев: Пробелы, табуляции и комментарии, которые не влияют на выполнение кода, удаляются для уменьшения размера файла.
- Оптимизация кода: Строки, разделяющие элементы JavaScript (такие как запятые и точки с запятой), приводятся к единому виду без лишних пробелов, что уменьшает общий размер кода.
Задачи и условия, которые выполняет код:
- Минификация JavaScript-кода: Главная задача файла — обработать JavaScript и вернуть его в минимизированном виде, что снижает объем передаваемых данных.
- Оптимизация загрузки страниц: Сокращение размера скриптов улучшает скорость загрузки страниц, что является важным аспектом для повышения производительности веб-приложений.
- Обработка различных синтаксических конструкций JavaScript: Код корректно обрабатывает строки, регулярные выражения и комментарии, чтобы они не влияли на минификацию. Это гарантирует, что функциональность кода сохраняется при его сжатии.
Заключение:
Файл jsmin.php является важным инструментом для разработки в Cotonti, предоставляя возможности для автоматической минификации JavaScript-кода. Это улучшает производительность веб-сайтов или приложений, снижая время загрузки и оптимизируя работу JavaScript на клиентской стороне.
/** * jsmin.php - PHP реализация JSMin от Douglas Crockford. * * Это практически прямой порт jsmin.c на PHP с небольшими * оптимизациями для PHP. В отличие от jsmin.c, который читает из stdin и * выводит в stdout, эта библиотека принимает строку в качестве входных данных * и возвращает другую строку в качестве выходных данных. * * Требуется PHP 5 или выше. * * Разрешается использовать эту версию библиотеки на тех же условиях, что и jsmin.c, * который имеет следующую лицензию: * * * @package JSMin // Указывает, что этот код относится к пакету JSMin. * @author Ryan Grove <[email protected]> // Автор порта на PHP. * @copyright 2002 Douglas Crockford <[email protected]> (jsmin.c) // Оригинальный автор jsmin.c. * @copyright 2008 Ryan Grove <[email protected]> (PHP port) // Автор PHP-версии. * @license http://opensource.org/licenses/mit-license.php MIT License // Указывает на лицензию MIT. * @version 1.1.1 (2008-03-02) // Версия и дата последнего обновления. * @link https://github.com/rgrove/jsmin-php/ // Ссылка на репозиторий. */ class JSMin { // Объявление класса JSMin, который выполняет минификацию JavaScript-кода. const ORD_LF = 10; // Константа, обозначающая ASCII-код символа перевода строки (LF). const ORD_SPACE = 32; // Константа, обозначающая ASCII-код пробела.
protected $a = ''; // Текущий символ, обрабатываемый в коде.
protected $b = ''; // Следующий значимый символ в коде.
protected $input = ''; // Исходный JavaScript-код, переданный для минификации.
protected $inputIndex = 0; // Текущая позиция (индекс) в строке кода.
protected $inputLength = 0; // Общая длина переданного JavaScript-кода.
protected $lookAhead = null; // Предварительно загруженный символ (если есть).
protected $output = ''; // Минифицированный (сжатый) JavaScript-код.
// -- Общедоступные статические методы ---------------------------------------
public static function minify($js) { // Статический метод для упрощенного вызова минификации.
$jsmin = new JSMin($js); // Создаёт новый экземпляр JSMin с переданным JavaScript-кодом.
return $jsmin->min(); // Вызывает метод min(), который выполняет минификацию и возвращает результат.
}
// -- Общедоступные методы экземпляра ----------------------------------------
public function __construct($input) { // Конструктор класса, принимает строку JavaScript-кода.
$this->input = str_replace("\r\n", "\n", $input); // Преобразует символы переноса строк из формата Windows в Unix.
$this->inputLength = strlen($this->input); // Определяет и сохраняет длину входного JavaScript-кода.
}
// -- Защищённые методы экземпляра --------------------------------------------
/* action — выполняет одно из трёх действий в зависимости от аргумента:
1 Выводит `a`. Копирует `b` в `a`. Получает следующий `b`.
2 Копирует `b` в `a`. Получает следующий `b` (удаляет `a`).
3 Получает следующий `b` (удаляет `b`).
action воспринимает строку как одиночный символ.
action распознаёт регулярное выражение, если перед ним стоит ( или , или =.
*/
protected function action($d) { // Метод выполняет одно из трёх действий в зависимости от переданного параметра.
switch($d) { // Определяет, какой случай обработки выполнять.
case 1: // Если $d равно 1.
$this->output .= $this->a; // Добавляет текущий символ `a` в выходной код.
case 2: // Если $d равно 2.
$this->a = $this->b; // Переносит `b` в `a`.
if ($this->a === "'" || $this->a === '"') { // Если `a` является кавычкой (начало строкового литерала).
for (;;) { // Бесконечный цикл обработки строки.
$this->output .= $this->a; // Добавляет `a` в выходной код.
$this->a = $this->get(); // Получает следующий символ.
if ($this->a === $this->b) { // Если встретилась закрывающая кавычка, выходит из цикла.
break; // Прерывает цикл.
}
if (ord($this->a) <= self::ORD_LF) { // Проверяет, не является ли символ управляющим символом новой строки.
throw new JSMinException('Незавершённый строковый литерал.'); // Вызывает исключение, если строка не завершена.
}
if ($this->a === '\\') { // Если встретился символ экранирования.
$this->output .= $this->a; // Добавляет `\` в выходной код.
$this->a = $this->get(); // Получает следующий символ после `\`.
}
}
}
case 3: // Если $d равно 3.
$this->b = $this->next(); // Получает следующий символ в `b`.
if ($this->b === '/' && ( // Проверяет, начинается ли `b` с `/` и является ли это началом регулярного выражения.
$this->a === '(' || $this->a === ',' || $this->a === '=' ||
$this->a === ':' || $this->a === '[' || $this->a === '!' ||
$this->a === '&' || $this->a === '|' || $this->a === '?' ||
$this->a === '{' || $this->a === '}' || $this->a === ';' ||
$this->a === "\n" )) { // Если перед `/` стоит один из перечисленных символов, значит, это регулярное выражение.
$this->output .= $this->a . $this->b; // Добавляет `a` и `b` (`/`) в выходной код.
for (;;) { // Бесконечный цикл обработки регулярного выражения.
$this->a = $this->get(); // Получает следующий символ.
if ($this->a === '[') { // Если встретилась открывающая `[` внутри регулярного выражения.
for (;;) { // Цикл обработки набора символов внутри `[...]`.
$this->output .= $this->a; // Добавляет `a` в выходной код.
$this->a = $this->get(); // Получает следующий символ.
if ($this->a === ']') { // Если встретилась закрывающая `]`, выход из цикла.
break; // Прерывает цикл.
} elseif ($this->a === '\\') { // Если встретился `\`, обрабатывает экранированный символ.
$this->output .= $this->a; // Добавляет `\` в выходной код.
$this->a = $this->get(); // Получает следующий символ после `\`.
} elseif (ord($this->a) <= self::ORD_LF) { // Если достигнут конец строки без закрытия `]`.
throw new JSMinException('Незавершённый набор символов в регулярном выражении.'); // Вызывает исключение.
}
}
} elseif ($this->a === '/') { // Если встретилась закрывающая `/`, завершает регулярное выражение.
break; // Прерывает цикл.
} elseif ($this->a === '\\') { // Если встретился `\`, обрабатывает экранированный символ.
$this->output .= $this->a; // Добавляет `\` в выходной код.
$this->a = $this->get(); // Получает следующий символ после `\`.
} elseif (ord($this->a) <= self::ORD_LF) { // Если достигнут конец строки без закрытия `/`.
throw new JSMinException('Незавершённое регулярное выражение.'); // Вызывает исключение.
}
$this->output .= $this->a; // Добавляет текущий символ `a` в выходной код.
}
$this->b = $this->next(); // Получает следующий символ после завершения обработки регулярного выражения.
}
}
}
protected function get() { // Метод для получения следующего символа из входных данных.
$c = $this->lookAhead; // Сохраняет значение предварительного просмотра символа в переменную `$c`.
$this->lookAhead = null; // Обнуляет предварительный просмотр символа.
if ($c === null) { // Если нет символа для предварительного просмотра (переменная `$c` пуста),
if ($this->inputIndex < $this->inputLength) { // и если индекс ещё не достиг конца строки,
$c = substr($this->input, $this->inputIndex, 1); // получает следующий символ из строки.
$this->inputIndex += 1; // Увеличивает индекс, чтобы двигаться к следующему символу.
} else { // Если достигнут конец строки,
$c = null; // устанавливает `$c` в `null`, что означает конец ввода.
}
}
if ($c === "\r") { // Если символ — это возврат каретки (Carriage Return),
return "\n"; // возвращает символ новой строки (перевод строки), заменяя `\r` на `\n`.
}
if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) { // Если символ — это конец строки, `null`, или пробельный символ,
return $c; // возвращает его без изменений.
}
return ' '; // В любом другом случае заменяет символ на пробел.
}
/* isAlphanum -- возвращает true, если символ является буквой, цифрой, подчеркиванием,
знаком доллара или не-ASCII символом.
*/
protected function isAlphaNum($c) { // Метод проверяет, является ли символ алфавитным или числовым.
if ($c === null || $c === false) { // Если символ равен null или false,
return false; // возвращает false.
}
return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1; // Если код символа больше 126 (не-ASCII символ), либо символ — это обратный слэш, либо символ является буквенно-цифровым или знаком доллара (проверяется с помощью регулярного выражения), возвращает true. В противном случае — false.
}
protected function min() { // Метод min() — основной процесс минификации.
$this->a = "\n"; // Инициализация переменной $a значением новой строки, начинается с символа новой строки.
$this->action(3); // Вызов метода action с аргументом 3, для выполнения действия с первым символом (инициализация).
while ($this->a !== null) { // Цикл продолжается до тех пор, пока переменная $a не станет null.
switch ($this->a) { // Проверка значения переменной $a, в зависимости от которого выполняется соответствующее действие.
case ' ': // Если $a является пробелом,
if ($this->isAlphaNum($this->b)) { // Если переменная $b является буквенно-цифровым символом,
$this->action(1); // Выполнить действие 1, что значит добавить символ $a в вывод и передвинуть указатель.
} else {
$this->action(2); // В противном случае выполнить действие 2, что значит пропустить пробел.
}
break; // Выход из блока case пробела.
case "\n": // Если $a является новой строкой,
switch ($this->b) { // Проверка значения переменной $b, чтобы определить, как поступить с новой строкой.
case '{': // Если $b — символ открывающей фигурной скобки,
case '[': // или открывающей квадратной скобки,
case '(': // или открывающей круглой скобки,
case '+': // или знака плюса,
case '-': // или знака минуса,
$this->action(1); // Выполняем действие 1, то есть сохраняем $a и продолжаем обработку, добавляем в вывод.
break; // Выход из блока case новой строки.
case ' ': // Если $b — пробел,
$this->action(3); // Выполняем действие 3, что означает просто пропуск пробела.
break;
default: // Если ни одно из предыдущих условий не выполнено,
if ($this->isAlphaNum($this->b)) { // Если $b является буквенно-цифровым символом,
$this->action(1); // Выполняем действие 1, добавляем $a в вывод.
}
else {
$this->action(2); // В противном случае выполняем действие 2, пропускаем символ.
}
}
break;
default: // Если $a не является пробелом или новой строкой,
switch ($this->b) { // Проверяем значение $b.
case ' ': // Если $b — пробел,
if ($this->isAlphaNum($this->a)) { // Если $a является буквенно-цифровым символом,
$this->action(1); // Выполняем действие 1, добавляем символ $a в вывод.
break;
}
$this->action(3); // Если $a не буквенно-цифровой символ, выполняем действие 3, пропускаем пробел.
break;
case "\n": // Если $b — новая строка,
switch ($this->a) { // Проверяем значение $a.
case '}': // Если $a — закрывающая фигурная скобка,
case ']': // или закрывающая квадратная скобка,
case ')': // или закрывающая круглая скобка,
case '+': // или знак плюса,
case '-': // или знак минуса,
case '"': // или кавычка,
case "'": // или апостроф,
$this->action(1); // Выполняем действие 1, добавляем символ $a в вывод.
break;
default: // Если $a не соответствует ни одному из перечисленных случаев,
if ($this->isAlphaNum($this->a)) { // Если $a — буквенно-цифровой символ,
$this->action(1); // Выполняем действие 1, добавляем $a в вывод.
}
else {
$this->action(3); // В противном случае выполняем действие 3, пропускаем символ.
}
}
break;
default: // Если $b не является пробелом или новой строкой,
$this->action(1); // Выполняем действие 1, добавляем символ в вывод.
break;
}
}
}
return $this->output; // Возвращаем результат минификации в виде строки.
}
Объяснение:
-
Основная цель метода
min(): Минификация входного JavaScript-кода, удаляя лишние пробелы, переносы строк и ненужные символы. Это выполняется через несколько уровней вложенных условий, которые проверяют символы и в зависимости от контекста (например, пробел или новая строка) выполняется соответствующее действие. -
Цикл и проверка символов: Цикл
whileпродолжается до тех пор, пока не обрабатываются все символы во входной строке, причем каждая итерация проверяет текущий символ и определяет, нужно ли его добавить в вывод, пропустить или выполнить другое действие. -
Использование метода
action(): Этот метод обрабатывает различные действия в зависимости от текущего контекста (например, добавление символа в результат или его пропуск). -
Действия с символами: В коде рассматриваются различные случаи для пробела, новой строки и других символов. В каждом случае определяется, нужно ли продолжать минификацию или пропустить символ (например, если символ — пробел, то решение зависит от того, следует ли оставить его или удалить).
Метод использует проверку условий для адаптации минификации под разные контексты в коде, чтобы результат был корректным и эффективно минифицированным JavaScript-кодом.
/* next -- get the next character, excluding comments. peek() is used to see
if a '/' is followed by a '/' or '*'.
*/
protected function next() { // Метод next() — получает следующий символ, исключая комментарии.
$c = $this->get(); // Получаем следующий символ с помощью метода get(), который учитывает предыдущие символы.
if ($c === '/') { // Если символ равен слэшу ("/"),
switch($this->peek()) { // Проверяем следующий символ с помощью peek(), чтобы выяснить, что следует за "/".
case '/': // Если следующий символ — слэш (начало однострочного комментария),
for (;;) { // Запускаем бесконечный цикл для пропуска содержимого комментария.
$c = (string) $this->get(); // Получаем следующий символ.
if (ord($c) <= self::ORD_LF) { // Если символ — это символ новой строки или меньше (по значению),
return $c; // Возвращаем символ новой строки, завершая комментарий.
}
}
case '*': // Если следующий символ — звездочка (начало многострочного комментария),
$this->get(); // Пропускаем звездочку.
for (;;) { // Запускаем бесконечный цикл для пропуска содержимого многострочного комментария.
switch($this->get()) { // Получаем следующий символ и проверяем его.
case '*': // Если символ — звездочка,
if ($this->peek() === '/') { // И следующий символ — слэш (закрывающая часть комментария),
$this->get(); // Пропускаем слэш.
return ' '; // Возвращаем пробел, что означает завершение комментария.
}
break;
case null: // Если символ равен null (конец ввода),
throw new JSMinException('Unterminated comment.'); // Бросаем исключение, так как комментарий не завершен.
}
}
default: // Если следующий символ не является ни слэшем, ни звездочкой,
return $c; // Возвращаем символ без изменений.
}
}
return $c; // Если символ не является слэшем, просто возвращаем его.
}
protected function peek() { // Метод peek() — смотрит на следующий символ, не изменяя текущего положения указателя.
$this->lookAhead = $this->get(); // Получаем следующий символ и сохраняем его в переменную lookAhead.
return $this->lookAhead; // Возвращаем символ, который будет использоваться для дальнейшей проверки.
}
Объяснение:
-
Метод
next(): Этот метод получает следующий символ, игнорируя комментарии (как однострочные, так и многострочные). Если встречается комментарий, метод пропускает его содержимое и продолжает обработку. -
Обработка однострочных комментариев (
//): Когда встречается символ/, метод используетpeek()для проверки следующего символа. Если это второй/, это означает начало однострочного комментария, и метод будет продолжать считывать символы, пока не встретит символ новой строки. -
Обработка многострочных комментариев (
/* */): Когда встречается символ/, метод проверяет, не является ли следующий символ звездочкой (*), что указывает на начало многострочного комментария. В таком случае метод пропускает все символы внутри комментария, пока не встретит закрывающую звездочку и слэш (*/). -
Метод
peek(): Этот метод используется для просмотра следующего символа, не двигая указатель на ввод, что позволяет проверить, что идет после текущего символа. Этот метод важен для определения типа комментария (однострочный или многострочный).
// -- Exceptions ---------------------------------------------------------------
class JSMinException extends Exception {} // Создаем класс исключения JSMinException, который наследует стандартное исключение PHP (Exception).
Объяснение:
- Этот фрагмент кода объявляет класс
JSMinException, который расширяет стандартное исключениеExceptionв PHP. Класс не добавляет дополнительной логики или свойств, но он позволяет создавать специфические исключения для обработки ошибок в процессе минификации JavaScript. - Использование этого класса позволяет идентифицировать ошибки, связанные с минификатором JS, как отдельные исключения, которые можно обрабатывать отдельно от других типов ошибок в программе.
Комментарии (0)
Автор контента
Оффлайн
Sodium Carbonate
Последняя авторизация: 19.07.2026 01:57
- Страница размещена: 30.01.2025 16:32
- Последнее обновление: 30.01.2025 16:45