Skip to content

Commit e6b4237

Browse files
committed
enh(php) Add support for constants and php 8.1 keywords
1 parent 91c5228 commit e6b4237

File tree

4 files changed

+148
-17
lines changed

4 files changed

+148
-17
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Grammars:
1919
- fix(clojure) Remove inconsistent/broken highlighting for metadata
2020
- enh(clojure) Add `punctuation` mode for commas.
2121
- enh(nsis) Update variables pattern (#3416) [idleberg][]
22+
- enh(php) Add support for constants and PHP 8.1 keywords [Wojciech Kania][]
2223

2324
Developer Tools:
2425

src/languages/php.js

Lines changed: 103 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,105 @@ Category: common
1111
* @returns {LanguageDetail}
1212
* */
1313
export default function(hljs) {
14+
const regex = hljs.regex;
15+
const LABEL = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*' +
16+
// negative look-ahead tries to avoid matching patterns that are not
17+
// Perl at all like $ident$, @ident@, etc.
18+
'(?![A-Za-z0-9])(?![$])';
19+
const PASCAL_CASE_CLASS_NAME = regex.concat("[A-Z]", LABEL);
1420
const VARIABLE = {
15-
className: 'variable',
16-
begin: '\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*' +
17-
// negative look-ahead tries to avoid matching patterns that are not
18-
// Perl at all like $ident$, @ident@, etc.
19-
`(?![A-Za-z0-9])(?![$])`
21+
scope: 'variable',
22+
match: '\\$+' + LABEL,
23+
};
24+
const CONSTANT_CALL = regex.concat(LABEL, "\\b(?!\\()");
25+
const CONSTANT = {
26+
variants: [
27+
{
28+
match: [
29+
/const/,
30+
/\s+/,
31+
LABEL,
32+
/\s*=/,
33+
],
34+
scope: {
35+
1: "keyword",
36+
3: "variable",
37+
},
38+
},
39+
{
40+
match: [
41+
regex.concat(
42+
/::/,
43+
regex.lookahead(/(?!class\b)/)
44+
),
45+
CONSTANT_CALL,
46+
],
47+
scope: {
48+
2: "variable",
49+
},
50+
},
51+
{
52+
match: [
53+
PASCAL_CASE_CLASS_NAME,
54+
regex.concat(
55+
"::",
56+
regex.lookahead(/(?!class\b)/)
57+
),
58+
CONSTANT_CALL,
59+
],
60+
scope: {
61+
1: "title.class",
62+
3: "variable",
63+
},
64+
},
65+
{
66+
match: [
67+
/::/,
68+
/class/,
69+
],
70+
scope: {
71+
2: "keyword",
72+
},
73+
},
74+
{
75+
match: [
76+
PASCAL_CASE_CLASS_NAME,
77+
/::/,
78+
/class/,
79+
],
80+
scope: {
81+
1: "title.class",
82+
3: "keyword",
83+
},
84+
}
85+
]
86+
};
87+
const CONSTRUCTOR = {
88+
variants: [
89+
{
90+
match: [
91+
/new/,
92+
/\s+/,
93+
regex.concat("\\?", PASCAL_CASE_CLASS_NAME),
94+
/\s*\(/,
95+
],
96+
scope: {
97+
1: "keyword",
98+
3: "title.class",
99+
},
100+
}
101+
]
20102
};
21103
const PREPROCESSOR = {
22-
className: 'meta',
104+
scope: 'meta',
23105
variants: [
24106
{ begin: /<\?php/, relevance: 10 }, // boost for obvious PHP
25107
{ begin: /<\?[=]?/ },
26108
{ begin: /\?>/ } // end php tag
27109
]
28110
};
29111
const SUBST = {
30-
className: 'subst',
112+
scope: 'subst',
31113
variants: [
32114
{ begin: /\$\w+/ },
33115
{ begin: /\{\$/, end: /\}/ }
@@ -46,7 +128,7 @@ export default function(hljs) {
46128
contains: hljs.QUOTE_STRING_MODE.contains.concat(SUBST),
47129
});
48130
const STRING = {
49-
className: 'string',
131+
scope: 'string',
50132
contains: [hljs.BACKSLASH_ESCAPE, PREPROCESSOR],
51133
variants: [
52134
hljs.inherit(SINGLE_QUOTED, {
@@ -61,7 +143,7 @@ export default function(hljs) {
61143
]
62144
};
63145
const NUMBER = {
64-
className: 'number',
146+
scope: 'number',
65147
variants: [
66148
{ begin: `\\b0b[01]+(?:_[01]+)*\\b` }, // Binary w/ underscore support
67149
{ begin: `\\b0o[0-7]+(?:_[0-7]+)*\\b` }, // Octals w/ underscore support
@@ -87,7 +169,7 @@ export default function(hljs) {
87169
'array abstract and as binary bool boolean break callable case catch class clone const continue declare ' +
88170
'default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile enum eval extends ' +
89171
'final finally float for foreach from global goto if implements instanceof insteadof int integer interface ' +
90-
'isset iterable list match|0 mixed new object or private protected public real return string switch throw trait ' +
172+
'isset iterable list match|0 mixed new never object or private protected public readonly real return string switch throw trait ' +
91173
'try unset use var void while xor yield',
92174
literal: 'false null true',
93175
built_in:
@@ -97,10 +179,10 @@ export default function(hljs) {
97179
'AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException UnhandledMatchError ' +
98180
// Reserved interfaces:
99181
// <https://www.php.net/manual/en/reserved.interfaces.php>
100-
'ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Stringable Throwable Traversable WeakReference WeakMap ' +
182+
'ArrayAccess BackedEnum Closure Fiber Generator Iterator IteratorAggregate Serializable Stringable Throwable Traversable UnitEnum WeakReference WeakMap ' +
101183
// Reserved classes:
102184
// <https://www.php.net/manual/en/reserved.classes.php>
103-
'Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass'
185+
'Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass',
104186
};
105187
return {
106188
case_insensitive: true,
@@ -114,7 +196,7 @@ export default function(hljs) {
114196
{
115197
contains: [
116198
{
117-
className: 'doctag',
199+
scope: 'doctag',
118200
begin: '@[A-Za-z]+'
119201
}
120202
]
@@ -130,15 +212,17 @@ export default function(hljs) {
130212
),
131213
PREPROCESSOR,
132214
{
133-
className: 'keyword', begin: /\$this\b/
215+
scope: 'keyword', begin: /\$this\b/
134216
},
135217
VARIABLE,
218+
CONSTANT,
219+
CONSTRUCTOR,
136220
{
137221
// swallow composed identifiers to avoid parsing them as keywords
138222
begin: /(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/
139223
},
140224
{
141-
className: 'function',
225+
scope: 'function',
142226
relevance: 0,
143227
beginKeywords: 'fn function', end: /[;{]/, excludeEnd: true,
144228
illegal: '[$%\\[]',
@@ -152,14 +236,16 @@ export default function(hljs) {
152236
endsParent: true
153237
},
154238
{
155-
className: 'params',
239+
scope: 'params',
156240
begin: '\\(', end: '\\)',
157241
excludeBegin: true,
158242
excludeEnd: true,
159243
keywords: KEYWORDS,
160244
contains: [
161245
'self',
162246
VARIABLE,
247+
CONSTANT,
248+
CONSTRUCTOR,
163249
hljs.C_BLOCK_COMMENT_MODE,
164250
STRING,
165251
NUMBER
@@ -168,7 +254,7 @@ export default function(hljs) {
168254
]
169255
},
170256
{
171-
className: 'class',
257+
scope: 'class',
172258
variants: [
173259
{ beginKeywords: "enum", illegal: /[($"]/ },
174260
{ beginKeywords: "class interface trait", illegal: /[:($"]/ }

test/markup/php/titles.expect.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Example</span> </span>{
2+
<span class="hljs-keyword">const </span><span class="hljs-variable">FOO</span>=<span class="hljs-string">&#x27;foo&#x27;</span>;
3+
4+
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
5+
<span class="hljs-keyword">public</span> <span class="hljs-keyword">readonly</span> <span class="hljs-keyword">string</span> <span class="hljs-variable">$name</span> = <span class="hljs-title class_">self::</span><span class="hljs-variable">FOO</span>
6+
</span>) </span>{}
7+
8+
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getClass</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span> </span>{
9+
<span class="hljs-keyword">return</span> <span class="hljs-title class_">DateTimeImmutable</span>::<span class="hljs-keyword">class</span>;
10+
}
11+
12+
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getClassFromSelf</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span> </span>{
13+
<span class="hljs-keyword">return</span> <span class="hljs-title class_">self</span>::<span class="hljs-keyword">class</span>;
14+
}
15+
16+
<span class="hljs-keyword">public</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getClassFromStaic</span>(<span class="hljs-params"></span>): <span class="hljs-title">string</span> </span>{
17+
<span class="hljs-keyword">return</span> <span class="hljs-title class_">static</span>::<span class="hljs-keyword">class</span>;
18+
}
19+
}
20+
21+
<span class="hljs-variable">$date</span> = DateTimeImmutable::createFromMutable(<span class="hljs-keyword">new</span> <span class="hljs-title class_">\DateTime</span>());
22+
<span class="hljs-keyword">echo</span> <span class="hljs-variable">$date</span>::<span class="hljs-keyword">class</span>;

test/markup/php/titles.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
final class Example {
2+
const FOO='foo';
3+
4+
public function __construct(
5+
public readonly string $name = self::FOO
6+
) {}
7+
8+
public function getClass(): string {
9+
return DateTimeImmutable::class;
10+
}
11+
12+
public function getClassFromSelf(): string {
13+
return self::class;
14+
}
15+
16+
public static function getClassFromStaic(): string {
17+
return static::class;
18+
}
19+
}
20+
21+
$date = DateTimeImmutable::createFromMutable(new \DateTime());
22+
echo $date::class;

0 commit comments

Comments
 (0)