- 教育
- 后端
- 前端
【免费下载链接】moodle
Moodle - the world's open source learning platform
导读
PHP CSS Parser(sabberworm/php-css-parser)是 Moodle 仓库public/lib/php-css-parser目录下内置的一个纯 PHP 实现的 CSS 解析库,它能把 CSS 文本解析为可编程操作的对象树(Document),允许开发者提取、增删改查样式规则后再重新渲染为(可优化的)CSS。本指南以该库的官方 README 为主体,结合 Moodle 仓库内的真实源码(public/lib/php-css-parser/src/)与应用实例(Boost 主题自动加前缀器),完整讲解安装、解析选项、对象模型、增删改操作、输出格式化以及四个实战用例,读完即可在 PHP 项目中独立完成"读 CSS → 改 CSS → 写 CSS"的全流程开发。
一、库的定位与仓库内置版本
该库核心能力一句话概括:A Parser for CSS Files written in PHP—— 将 CSS 文件提取为数据结构的解析器,允许对该结构进行修改,并以(优化后的)CSS 形式输出。
在 Moodle 仓库中,它位于 public/lib/php-css-parser/,目录下的 readme_moodle.txt 记录了它随 Moodle 发布的导入流程:通过composer require sabberworm/php-css-parser拉取后再复制进lib/php-css-parser,并额外应用了上游 PR #173 的补丁。因此仓库中的这份代码与 Composer 发布版本基本一致,可放心按官方 README 的方式使用。
从 composer.json 可以看到它的工程约束:
- PHP 版本支持:
^5.6.20 || ^7.0.0 || ~8.0.0 ~8.4.0(覆盖面很广,Moodle 各版本均可运行); - 必需扩展:
ext-iconv; - 建议扩展:
ext-mbstring("for parsing UTF-8 CSS",用于解析 UTF-8 CSS); - 命名空间:
Sabberworm\CSS\通过 PSR-4 映射到src/目录; - 许可证:MIT。
二、安装与快速上手(Extraction)
2.1 Composer 安装
composer require sabberworm/php-css-parser2.2 解析 CSS 文本
使用解析器需要先new一个实例,构造函数形式为:
new \Sabberworm\CSS\Parser($css);读取文件并解析的完整流程:
$parser = new \Sabberworm\CSS\Parser(file_get_contents('somefile.css')); $cssDocument = $parser->parse();从源码看,Parser.php 的构造函数会以传入的文本和可选的Settings(默认Settings::create())构造一个 ParserState 状态机,第三个参数是起始行号(默认 1);而parse()方法直接委托给Document::parse($oParserState)(见 Document.php),最终返回一个Document对象——它就是整棵 CSS 对象树的根节点。Document内部通过CSSList::parseList逐条解析顶层内容,因此能同时容纳声明块、@import、@charset以及各种 at-rule。
解析得到的结构可被自由修改,修改后再输出。
三、解析选项(Settings)
Moodle 内置的 Settings.php 提供了三个可配置项,均采用链式(fluent)API。
3.1 Charset(默认字符集)
withDefaultCharset()设置的字符集仅当 CSS 中不含@charset声明时才会生效,默认值就是 UTF-8(源码中$sDefaultCharset = 'utf-8')。因此不改字符集时完全无需创建 Settings 对象:
$settings = \Sabberworm\CSS\Settings::create() ->withDefaultCharset('windows-1252'); $parser = new \Sabberworm\CSS\Parser($css, $settings);底层上,ParserState.php 的构造函数会用$oParserSettings->sDefaultCharset调用setCharset(),再据此对文本做字符切分;解析过程中一旦遇到@charset声明则会覆盖它(详见 CHANGELOG 中关于 charset 的演进)。
3.2 严格解析(Strict parsing)
默认情况下解析器是"宽容模式"(bLenientParsing = true),遇到非法/未知结构时尝试忽略并继续解析;若希望遇到非法结构直接抛出异常,可配置:
$parser = new \Sabberworm\CSS\Parser( file_get_contents('somefile.css'), \Sabberworm\CSS\Settings::create()->beStrict() );注意:开启严格模式还会禁用一条针对 IE 旧式filter规则非引号变体的解析兼容补丁。
beStrict()的内部实现是withLenientParsing(false)(见 Settings.php)。宽容/严格两种行为的差异在 RuleSet.php 的parseRuleSet中有直接体现:宽容模式下,Rule::parse抛出的UnexpectedTokenException会被捕获,解析器通过consumeUntil跳过直到换行/分号/右括号的内容来"消化"坏 token;严格模式下则直接让异常上抛。
3.3 禁用多字节函数(Disable multibyte functions)
默认bMultibyteSupport取extension_loaded('mbstring')(即系统装了 mbstring 就默认开启)。可通过withMultibyteSupport(false)关闭,让库改用普通字符串函数替代mb_strlen、mb_substr、mb_strpos等,以获得更快的解析速度:
$settings = \Sabberworm\CSS\Settings::create()->withMultibyteSupport(false); $parser = new \Sabberworm\CSS\Parser($css, $settings);官方提醒:绝大多数情况下(包括 UTF-8 文件)这样都能正常工作,因为多字节字符基本都出现在字符串字面量里;但不建议用它处理不可控的外部输入,因为该路径没有被测试用例充分覆盖。
3.4 三种选项速查表
| 选项 | 方法 | 默认值 | 说明 |
|---|---|---|---|
| 默认字符集 | withDefaultCharset($charset) | 'utf-8' | 仅在没有@charset声明时生效 |
| 宽容解析 | withLenientParsing(true)/beStrict() | true(宽容) | 宽容=忽略非法结构继续解析;严格=抛异常 |
| 多字节支持 | withMultibyteSupport(bool) | 取决于mbstring是否加载 | 关闭可提速,但不建议用于不可控输入 |
四、对象模型:六大核心类型
解析结果主要由五种基本类型构成:CSSList、RuleSet、Rule、Selector和Value;另外还有两种不常用到的辅助类型:Import和Charset。它们全部位于 src/ 下,对应目录结构一目了然:CSSList/、RuleSet/、Rule/、Property/(含 Selector、Charset、Import 等)、Value/。
4.1 CSSList
CSSList是通用 CSS 容器(见 CSSList.php),最典型的实现是Document(parse()的返回值),一般装的是带选择器的声明块,但也可能包含 at-rules、@charset声明等。其子类包括:
CSSBlockList(带块的列表基类,见 CSSBlockList.php);Document(文档根节点,见 Document.php);KeyFrame(@keyframes专用列表,见 KeyFrame.php);AtRuleBlockList(@media等带块 at-rule 列表,见 AtRuleBlockList.php)。
访问CSSList中的条目(比如$parser->parse()返回的文档)使用getContents(),然后遍历集合并用instanceof判断条目是另一个CSSList、RuleSet、Import还是Charset。要向既有CSSList追加新条目(如选择器、媒体查询等),用对应类的构造函数创建对象后调用append($oItem)方法。
4.2 RuleSet
RuleSet(见 RuleSet.php)是单条规则的容器,最常见的形态是"被选择器约束的规则集"。两个具体子类:
AtRuleSet(见 AtRuleSet.php)—— 通用 at-rule 规则集,专门覆盖未被@import、@charset、@media等专门类处理的 at-rule,典型例子就是@font-face;DeclarationBlock(见 DeclarationBlock.php)—— 被Selector约束的RuleSet,内部持有选择器对象数组(对应 CSS 中的逗号分隔选择器列表)以及应用到匹配元素上的规则。
嵌套规则:CSSList可以包含其它CSSList(以及Import、Charset),而RuleSet只能包含Rule。
操作RuleSet使用三个方法:addRule(Rule $rule)、getRules()和removeRule($rule)。其中removeRule()的参数可以是Rule对象也可以是规则名;规则名后追加一个短横线即可删除所有相关规则(例如'font-'会同时删掉font-size、font-weight以及font本身)。
4.3 Rule
Rule(见 Rule.php)只有两个核心成员:字符串键(规则名)和对应的Value;同时它内部还有bIsImportant布尔标记,用来记录!important(示例 2 的 var_dump 中color: red !important即表现为bIsImportant => bool(true))。
4.4 Value 及其子类
Value(见 Value.php)是抽象基类,只定义了render方法。原子值类型的具体子类:
Size(见 Size.php)—— 由一个数值size和一个单位组成(如1.6em、0px、2%);Color(见 Color.php)—— 颜色可用#rrggbb、#rgb或schema(val1, val2, …)形式输入,但内部一律存储为('s' => val1, 'c' => val2, 'h' => val3, …)这种数组结构,并以第二种形式输出;CSSString(见 CSSString.php)—— 带引号字符串的包装器,用于与关键字区分,输出时一律使用双引号;URL(见 URL.php)—— CSS 中的 URL,输出时一律使用URL("")记号(如示例 1 中src: url("../media/cr.ttf"))。
Value下还有另一个抽象子类ValueList(见 ValueList.php):表示由某种分隔符(多数是,、空格或/)分隔的Value列表。ValueList又分两种:
RuleValueList(见 RuleValueList.php)—— 默认类型,表示所有多值规则,例如font: bold 12px/3 Helvetica, Verdana, sans-serif;的值就是一个"空白分隔列表",其中bold是原始值、12px/3是斜杠分隔列表、Helvetica, Verdana, sans-serif是逗号分隔列表;CSSFunction(见 CSSFunction.php)—— 特殊的值类型,含函数名,其值即函数参数;同时支持等号分隔的参数列表,如filter: alpha(opacity=90);。
仓库还提供了CalcFunction(calc()计算函数,见 CalcFunction.php)、CalcRuleValueList(见 CalcRuleValueList.php)、PrimitiveValue(见 PrimitiveValue.php)等扩展类型,可见其对现代 CSS 语法(calc()、grid 的LineName等)也有专门支持。
4.5 Document 的便捷方法(Convenience methods)
Document上提供了一批便于查找、修改、删除规则的便捷方法(见 Document.php):
getAllDeclarationBlocks()—— 递归返回全部DeclarationBlock,无论选择器嵌套多深;别名getAllSelectors()(后者已标记 deprecated,将在 9.0 移除,建议使用前者);getAllRuleSets()—— 递归返回全部RuleSet;getAllValues($mElement = null, $bSearchInFunctionArguments = false)—— 找出Rule内的全部Value对象,可按规则名过滤,也可决定是否搜索函数参数;getSelectorsBySpecificity($sSpecificitySearch)—— 按特异性过滤选择器(如getSelectorsBySpecificity('>= 100'));- 另有
expandShorthands()/createShorthands()(展开/合并简写属性,均已标注 deprecated,将在 9.0 移除)。
五、实战用例:解析 → 修改 → 输出
5.1 用例一:给所有选择器添加 ID 前缀
$myId = "#my_id"; $parser = new \Sabberworm\CSS\Parser($css); $cssDocument = $parser->parse(); foreach ($cssDocument->getAllDeclarationBlocks() as $block) { foreach ($block->getSelectors() as $selector) { // 遍历一个选择器内的所有部分(逗号分隔的字符串),并前置 ID。 $selector->setSelector($myId.' '.$selector->getSelector()); } }这个用例展示了Document::getAllDeclarationBlocks()与DeclarationBlock::getSelectors()+Selector::setSelector()的组合——无需关心选择器嵌套在多少层@media里,一次性全局改写选择器。
5.2 用例二:把所有绝对尺寸缩小一半
$parser = new \Sabberworm\CSS\Parser($css); $cssDocument = $parser->parse(); foreach ($cssDocument->getAllValues() as $value) { if ($value instanceof CSSSize && !$value->isRelative()) { $value->setSize($value->getSize() / 2); } }Size::isRelative()用来判断单位是否为相对单位(em、%、vh等),setSize()则直接修改数值。注意示例中的CSSSize实际类名应为Sabberworm\CSS\Value\Size(完整类名见 Size.php)。
5.3 用例三:批量删除不需要的规则
$parser = new \Sabberworm\CSS\Parser($css); $cssDocument = $parser->parse(); foreach($cssDocument->getAllRuleSets() as $oRuleSet) { // 注意:追加的短横线会删除所有以 `font-` 开头的规则 // (如 font-size、font-weight 等),以及可能存在的 `font` 规则本身。 $oRuleSet->removeRule('font-'); $oRuleSet->removeRule('cursor'); }这正是 4.2 节所述removeRule()通配行为的落地:'font-'前缀匹配把所有font-*与font一并清掉,'cursor'则精确删除该属性。
5.4 输出
把整个 CSS 文档输出到变量,直接调用->render():
$parser = new \Sabberworm\CSS\Parser(file_get_contents('somefile.css')); $cssDocument = $parser->parse(); print $cssDocument->render();想要自定义格式,传入一个\Sabberworm\CSS\OutputFormat实例:
$format = \Sabberworm\CSS\OutputFormat::create() ->indentWithSpaces(4)->setSpaceBetweenRules("\n"); print $cssDocument->render($format);或者使用两个预定义格式:
print $cssDocument->render(Sabberworm\CSS\OutputFormat::createPretty()); print $cssDocument->render(Sabberworm\CSS\OutputFormat::createCompact());输出格式化的全部能力可参考官方 README 指引的tests/OutputFormatTest.php(对应测试在仓库 public/lib/php-css-parser/tests/ 下)。
六、OutputFormat 的格式能力(源码级展开)
README 只给出三个输出示例,但 Moodle 内置的 OutputFormat.php 提供了远超于此的格式化控制点,这里做源码级展开:
- 字符串引号风格:
$sStringQuotingType(默认",可换'); - 颜色输出:
$bRGBHashNotation = true,尽可能输出#rrggbb哈希记法; - 末条规则分号:
$bSemicolonAfterLastRule = true,设为false可省略声明块最后一条规则后的分号; - 各类空格:
sSpaceAfterRuleName(属性名后的空格,默认 1 个空格)、sSpaceBeforeRules、sSpaceAfterRules、sSpaceBetweenRules、sSpaceBeforeBlocks、sSpaceAfterBlocks、sSpaceBetweenBlocks(默认"\n")、sSpaceBeforeOpeningBrace(默认 1 空格)等; - 选择器分隔:
sSpaceBeforeSelectorSeparator/sSpaceAfterSelectorSeparator(默认后者为 1 空格),控制逗号分隔选择器两边的空白; - 值列表分隔:
sSpaceBeforeListArgumentSeparator/sSpaceAfterListArgumentSeparator; - 缩进:
$sIndentation(默认"\t"),可用indentWithTabs($iNumber)或indentWithSpaces($iNumber)设置; - 异常与注释:
bIgnoreExceptions(beLenient()开启)、bRenderComments(是否渲染注释)。
set()方法支持通配符批量设置——例如set('Space*Rules', "\n")会同时展开为SpaceBeforeRules、SpaceBetweenRules、SpaceAfterRules三个字段(见 OutputFormat.php),这正是createPretty()与createCompact()两个预置格式的实现基础:
createCompact():把所有Space*Rules、Space*Blocks置空,并取消SpaceAfterRuleName、SpaceBeforeOpeningBrace、SpaceAfterSelectorSeparator,关闭注释渲染,得到最小体积输出;createPretty():把Space*Rules、Space*Blocks设为"\n"、SpaceBetweenBlocks设为"\n\n"、逗号分隔后加空格、开启注释渲染,得到易读的美化输出。
此外,格式化参数默认(即render()不传参时)是全新OutputFormat,此时保留原始的空格设置但不会渲染注释(bRenderComments = false)。
七、完整示例:输入、内部结构与输出
7.1 示例 1:At-Rules(@charset / @font-face / @keyframes)
输入 CSS:
@charset "utf-8"; @font-face { font-family: "CrassRoots"; src: url("../media/cr.ttf"); } html, body { font-size: 1.6em; } @keyframes mymove { from { top: 0px; } to { top: 200px; } }结构(var_dump() 节选)
class Sabberworm\CSS\CSSList\Document#4 (2) { protected $aContents => array(4) { [0] => class Sabberworm\CSS\Property\Charset#6 (2) { private $sCharset => class Sabberworm\CSS\Value\CSSString#5 (2) { private $sString => string(5) "utf-8" protected $iLineNo => int(1) } protected $iLineNo => int(1) } [1] => class Sabberworm\CSS\RuleSet\AtRuleSet#7 (4) { private $sType => string(9) "font-face" private $sArgs => string(0) "" private $aRules => array(2) { 'font-family' => array(1) { [0] => class Sabberworm\CSS\Rule\Rule#8 (4) { private $sRule => string(11) "font-family" private $mValue => class Sabberworm\CSS\Value\CSSString#9 (2) { private $sString => string(10) "CrassRoots" protected $iLineNo => int(4) } private $bIsImportant => bool(false) protected $iLineNo => int(4) } } 'src' => array(1) { [0] => class Sabberworm\CSS\Rule\Rule#10 (4) { private $sRule => string(3) "src" private $mValue => class Sabberworm\CSS\Value\URL#11 (2) { private $oURL => class Sabberworm\CSS\Value\CSSString#12 (2) { private $sString => string(15) "../media/cr.ttf" protected $iLineNo => int(5) } protected $iLineNo => int(5) } private $bIsImportant => bool(false) protected $iLineNo => int(5) } } } protected $iLineNo => int(3) } [2] => class Sabberworm\CSS\RuleSet\DeclarationBlock#13 (3) { private $aSelectors => array(2) { [0] => class Sabberworm\CSS\Property\Selector#14 (2) { private $sSelector => string(4) "html" private $iSpecificity => NULL } [1] => class Sabberworm\CSS\Property\Selector#15 (2) { private $sSelector => string(4) "body" private $iSpecificity => NULL } } private $aRules => array(1) { 'font-size' => array(1) { [0] => class Sabberworm\CSS\Rule\Rule#16 (4) { private $sRule => string(9) "font-size" private $mValue => class Sabberworm\CSS\Value\Size#17 (4) { private $fSize => double(1.6) private $sUnit => string(2) "em" private $bIsColorComponent => bool(false) protected $iLineNo => int(9) } private $bIsImportant => bool(false) protected $iLineNo => int(9) } } } protected $iLineNo => int(8) } [3] => class Sabberworm\CSS\CSSList\KeyFrame#18 (4) { private $vendorKeyFrame => string(9) "keyframes" private $animationName => string(6) "mymove" protected $aContents => array(2) { [0] => class Sabberworm\CSS\RuleSet\DeclarationBlock#19 (3) { private $aSelectors => array(1) { [0] => class Sabberworm\CSS\Property\Selector#20 (2) { private $sSelector => string(4) "from" private $iSpecificity => NULL } } private $aRules => array(1) { 'top' => array(1) { [0] => class Sabberworm\CSS\Rule\Rule#21 (4) { private $sRule => string(3) "top" private $mValue => class Sabberworm\CSS\Value\Size#22 (4) { private $fSize => double(0) private $sUnit => string(2) "px" private $bIsColorComponent => bool(false) protected $iLineNo => int(13) } private $bIsImportant => bool(false) protected $iLineNo => int(13) } } } protected $iLineNo => int(13) } [2] => class Sabberworm\CSS\RuleSet\DeclarationBlock#23 (3) { private $aSelectors => array(1) { [0] => class Sabberworm\CSS\Property\Selector#24 (2) { private $sSelector => string(2) "to" private $iSpecificity => NULL } } private $aRules => array(1) { 'top' => array(1) { [0] => class Sabberworm\CSS\Rule\Rule#25 (4) { private $sRule => string(3) "top" private $mValue => class Sabberworm\CSS\Value\Size#26 (4) { private $fSize => double(200) private $sUnit => string(2) "px" private $bIsColorComponent => bool(false) protected $iLineNo => int(14) } private $bIsImportant => bool(false) protected $iLineNo => int(14) } } } protected $iLineNo => int(14) } } protected $iLineNo => int(12) } } protected $iLineNo => int(1) }输出(render()):
@charset "utf-8"; @font-face {font-family: "CrassRoots";src: url("../media/cr.ttf");} html, body {font-size: 1.6em;} @keyframes mymove {from {top: 0px;} to {top: 200px;}}结构解读:@charset被解析为Charset属性;@font-face被解析为AtRuleSet(sType = "font-face");html, body是一个带两个Selector的DeclarationBlock;@keyframes被解析为专门的KeyFrame列表,其内部的from/to各自是独立DeclarationBlock。注意Size的bIsColorComponent = false标记表明该尺寸不是颜色分量(用于区分 0~255 数值的颜色分量与普通尺寸,见 Size.php)。
7.2 示例 2:Values(多值规则与 !important)
输入 CSS:
#header { margin: 10px 2em 1cm 2%; font-family: Verdana, Helvetica, "Gill Sans", sans-serif; color: red !important; }结构(var_dump() 节选)
class Sabberworm\CSS\CSSList\Document#4 (2) { protected $aContents => array(1) { [0] => class Sabberworm\CSS\RuleSet\DeclarationBlock#5 (3) { private $aSelectors => array(1) { [0] => class Sabberworm\CSS\Property\Selector#6 (2) { private $sSelector => string(7) "#header" private $iSpecificity => NULL } } private $aRules => array(3) { 'margin' => array(1) { [0] => class Sabberworm\CSS\Rule\Rule#7 (4) { private $sRule => string(6) "margin" private $mValue => class Sabberworm\CSS\Value\RuleValueList#12 (3) { protected $aComponents => array(4) { [0] => class Sabberworm\CSS\Value\Size#8 (4) { private $fSize => double(10) private $sUnit => string(2) "px" ... } [1] => class Sabberworm\CSS\Value\Size#9 (4) { private $fSize => double(2) private $sUnit => string(2) "em" ... } [2] => class Sabberworm\CSS\Value\Size#10 (4) { private $fSize => double(1) private $sUnit => string(2) "cm" ... } [3] => class Sabberworm\CSS\Value\Size#11 (4) { private $fSize => double(2) private $sUnit => string(1) "%" ... } } protected $sSeparator => string(1) " " protected $iLineNo => int(2) } private $bIsImportant => bool(false) protected $iLineNo => int(2) } } 'font-family' => array(1) { [0] => class Sabberworm\CSS\Rule\Rule#13 (4) { private $sRule => string(11) "font-family" private $mValue => class Sabberworm\CSS\Value\RuleValueList#15 (3) { protected $aComponents => array(4) { [0] => string(7) "Verdana" [1] => string(9) "Helvetica" [2] => class Sabberworm\CSS\Value\CSSString#14 (2) { private $sString => string(9) "Gill Sans" ... } [3] => string(10) "sans-serif" } protected $sSeparator => string(1) "," protected $iLineNo => int(3) } private $bIsImportant => bool(false) protected $iLineNo => int(3) } } 'color' => array(1) { [0] => class Sabberworm\CSS\Rule\Rule#16 (4) { private $sRule => string(5) "color" private $mValue => string(3) "red" private $bIsImportant => bool(true) protected $iLineNo => int(4) } } } protected $iLineNo => int(1) } } protected $iLineNo => int(1) }输出(render()):
#header {margin: 10px 2em 1cm 2%;font-family: Verdana,Helvetica,"Gill Sans",sans-serif;color: red !important;}结构解读:margin的四个值组成一个以空格(sSeparator = " ")分隔的RuleValueList,每个值都是带单位的Size;font-family是以逗号(sSeparator = ",")分隔的RuleValueList,其中无引号的Verdana等是原始字符串、带引号的"Gill Sans"是CSSString;color: red !important中red被保留为普通字符串关键字,而!important被记录在Rule的bIsImportant = true上。
八、Moodle 中的真实应用:Boost 主题自动加前缀器
README 描述的这套对象模型在 Moodle 内部有直接落地。Moodle 的默认主题 Boost 使用 autoprefixer.php 对主题 CSS 做自动厂商前缀处理,该文件顶部大量use Sabberworm\CSS\...导入(CSSList、Document、KeyFrame、OutputFormat、Parser、AtRule、Selector、Rule、AtRuleSet、DeclarationBlock、RuleSet、Settings、CSSFunction、CSSString、PrimitiveValue、RuleValueList、Size、ValueList),完全是对本库对象模型的系统化使用。
其核心流程(从源码结构看):
- 用
Parser解析 SCSS 编译后的 CSS 文本,得到Document对象树; processBlock()递归遍历CSSList($block->getContents()),用instanceof区分AtRule/CSSList/RuleSet三种节点(见 autoprefixer.php):遇到AtRule(尤其KeyFrame)时克隆并生成带-webkit-等前缀的变体,用insert()插回原列表;遇到嵌套CSSList则递归;遇到RuleSet则交给processDeclaration()处理;processDeclaration()遍历声明块内的Rule,对需要前缀的属性名做改写(见 autoprefixer.php 起的逻辑)。
这正体现了 README 中"用instanceof检查节点类型"与"CSSList可递归包含"等描述的实际工程价值——对象树模型让"遍历、克隆、插入、改写"这类 CSS 转换操作变得声明式且安全。
九、To-Do 与已知边界
官方 README 明确列出了尚未实现的能力,使用前应了解这些边界:
- 更多便捷方法(如
selectorsWithElement($sId/Class/TagName)、attributesOfType($type)、removeAttributesOfType($type))尚待补充; - 真正的多字节支持尚不完善:目前仅支持"前 255 个码点都只占一字节且与 ASCII 一致"的多字节字符集(UTF-8 恰好符合该描述),这与 3.3 节"关闭多字节函数通常没问题"的说明相互印证;
- 命名颜色支持(用
Color对象而非匿名字符串字面量)尚在规划中——这也是示例 2 中red被保留为普通字符串的原因。
十、测试与维护
官方 README 建议:运行全部单元测试,先composer install安装 phpunit,再执行./vendor/bin/phpunit。对应的测试用例位于仓库 public/lib/php-css-parser/tests/ 目录(含官方 README 提到的OutputFormatTest.php)。此外 composer.json 中还配置了 PHP CS Fixer、PHP_CodeSniffer、PHPStan 等静态检查脚本(composer ci),可一键执行ci:php:fixer、ci:php:sniffer、ci:php:stan。
结语
PHP CSS Parser 用一套清晰的对象模型(Document → CSSList → RuleSet → Rule → Value)把 CSS 从"字符串"升级为"可编程结构"。结合本仓库的 Parser.php、Settings.php、OutputFormat.php 等源码,以及 Boost 主题 autoprefixer 的真实用例,无论是做主题定制、样式清理、批量改写还是样式压缩,你都可以像操作普通 PHP 对象一样安全地"读-改-写"CSS。
- 教育
- 后端
- 前端
【免费下载链接】moodle
Moodle - the world's open source learning platform
相关推荐
Moodle 内置的 PHP CSS Parser:解析、操作与输出 CSS 的完整版本演进指南
Moodle 内置的 PHP CSS Parser:解析、操作与输出 CSS 的完整版本演进指南 本文以 Moodle 仓库内置的第三方库 sabberworm
教育后端前端Open WebUI 知识库实战指南:3 步跑通文档问答,附向量库选型与避坑
Open WebUI 知识库实战指南:3 步跑通文档问答,附向量库选型与避坑 想把手头一摞内部文档直接喂给大模型,让它答得有理有据?Open WebUI 内置的
人工智能大模型AI 应用RAGAI Agent本地部署交互助手后端前端深入理解Kotlin/Native构建输出:文件结构与内容解析指南
深入理解Kotlin/Native构建输出:文件结构与内容解析指南 Kotlin/Native作为JetBrains推出的跨平台开发技术,允许开发者使用Kotl
编程语言编译器标准库语言运行时
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考