xref: /PHP-Parser/lib/PhpParser/Modifiers.php (revision b493c51c)
1<?php declare(strict_types=1);
2
3namespace PhpParser;
4
5/**
6 * Modifiers used (as a bit mask) by various flags subnodes, for example on classes, functions,
7 * properties and constants.
8 */
9final class Modifiers {
10    public const PUBLIC    =  1;
11    public const PROTECTED =  2;
12    public const PRIVATE   =  4;
13    public const STATIC    =  8;
14    public const ABSTRACT  = 16;
15    public const FINAL     = 32;
16    public const READONLY  = 64;
17    public const PUBLIC_SET = 128;
18    public const PROTECTED_SET = 256;
19    public const PRIVATE_SET = 512;
20
21    public const VISIBILITY_MASK = self::PUBLIC | self::PROTECTED | self::PRIVATE;
22
23    public const VISIBILITY_SET_MASK = self::PUBLIC_SET | self::PROTECTED_SET | self::PRIVATE_SET;
24
25    private const TO_STRING_MAP = [
26        self::PUBLIC  => 'public',
27        self::PROTECTED => 'protected',
28        self::PRIVATE => 'private',
29        self::STATIC  => 'static',
30        self::ABSTRACT => 'abstract',
31        self::FINAL  => 'final',
32        self::READONLY  => 'readonly',
33        self::PUBLIC_SET => 'public(set)',
34        self::PROTECTED_SET => 'protected(set)',
35        self::PRIVATE_SET => 'private(set)',
36    ];
37
38    public static function toString(int $modifier): string {
39        if (!isset(self::TO_STRING_MAP[$modifier])) {
40            throw new \InvalidArgumentException("Unknown modifier $modifier");
41        }
42        return self::TO_STRING_MAP[$modifier];
43    }
44
45    private static function isValidModifier(int $modifier): bool {
46        $isPow2 = ($modifier & ($modifier - 1)) == 0 && $modifier != 0;
47        return $isPow2 && $modifier <= self::PRIVATE_SET;
48    }
49
50    /**
51     * @internal
52     */
53    public static function verifyClassModifier(int $a, int $b): void {
54        assert(self::isValidModifier($b));
55        if (($a & $b) != 0) {
56            throw new Error(
57                'Multiple ' . self::toString($b) . ' modifiers are not allowed');
58        }
59
60        if ($a & 48 && $b & 48) {
61            throw new Error('Cannot use the final modifier on an abstract class');
62        }
63    }
64
65    /**
66     * @internal
67     */
68    public static function verifyModifier(int $a, int $b): void {
69        assert(self::isValidModifier($b));
70        if (($a & Modifiers::VISIBILITY_MASK && $b & Modifiers::VISIBILITY_MASK) ||
71            ($a & Modifiers::VISIBILITY_SET_MASK && $b & Modifiers::VISIBILITY_SET_MASK)
72        ) {
73            throw new Error('Multiple access type modifiers are not allowed');
74        }
75
76        if (($a & $b) != 0) {
77            throw new Error(
78                'Multiple ' . self::toString($b) . ' modifiers are not allowed');
79        }
80
81        if ($a & 48 && $b & 48) {
82            throw new Error('Cannot use the final modifier on an abstract class member');
83        }
84    }
85}
86