ReferenceTrait   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 126
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 0
loc 126
c 0
b 0
f 0
wmc 15
lcom 1
cbo 0
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A setReferencePattern() 0 7 1
A deReference() 0 14 4
A deReferenceString() 0 18 4
A checkValue() 0 15 3
A resolveReference() 0 7 2
A resolveUnknown() 0 4 1
getReference() 0 1 ?
1
<?php
2
3
/**
4
 * Phoole (PHP7.2+)
5
 *
6
 * @category  Library
7
 * @package   Phoole\Base
8
 * @copyright Copyright (c) 2019 Hong Zhang
9
 */
10
declare(strict_types=1);
11
12
namespace Phoole\Base\Reference;
13
14
/**
15
 * ReferenceTrait
16
 *
17
 * @package Phoole\Base
18
 */
19
trait ReferenceTrait
20
{
21
    /**
22
     * default is '${' and '}'
23
     *
24
     * @var string
25
     */
26
    protected $ref_pattern = '~(\$\{(\w((?!\$\{|\}).)*)\})~';
27
28
    /**
29
     * @inheritDoc
30
     */
31
    public function setReferencePattern(string $start, string $end): object
32
    {
33
        $s = preg_quote($start);
34
        $e = preg_quote($end);
35
        $this->ref_pattern = sprintf("~(%s(\w((?!%s|%s).)*)%s)~", $s, $s, $e, $e);
36
        return $this;
37
    }
38
39
    /**
40
     * {@inheritDoc}
41
     */
42
    public function deReference(&$subject): void
43
    {
44
        if (is_string($subject)) {
45
            $subject = $this->deReferenceString($subject);
46
        }
47
48
        if (!is_array($subject)) {
49
            return;
50
        }
51
52
        foreach ($subject as &$data) {
53
            $this->dereference($data);
54
        }
55
    }
56
57
    /**
58
     * Replace all references in the target string (recursively)
59
     *
60
     * @param  string $subject
61
     * @return mixed
62
     * @throws \RuntimeException if bad thing happens
63
     */
64
    protected function deReferenceString(string $subject)
65
    {
66
        $loop = 0;
67
        // recursive matching in string
68
        while (preg_match($this->ref_pattern, $subject, $matched)) {
69
            if ($loop++ > 20) {
70
                throw new \RuntimeException("Loop in resolving $subject");
71
            }
72
73
            $ref = $this->resolveReference($matched[2]);
74
            if (is_string($ref)) {
75
                $subject = str_replace($matched[1], $ref, $subject);
76
            } else {
77
                return $this->checkValue($ref, $subject, $matched[1]);
78
            }
79
        }
80
        return $subject;
81
    }
82
83
    /**
84
     * Check dereferenced value
85
     *
86
     * @param  mixed  $value
87
     * @param  string $subject  the subject to dereference
88
     * @param  string $matched  the matched reference
89
     * @return mixed
90
     * @throws \RuntimeException if $subject malformed
91
     */
92
    protected function checkValue($value, string $subject, string $matched)
93
    {
94
        // reference not resolved
95
        if (is_null($value)) {
96
            return $this->resolveUnknown($subject, $matched);
97
        }
98
99
        // malformed subject
100
        if ($subject != $matched) {
101
            throw new \RuntimeException("Error in resolving $matched");
102
        }
103
104
        // good match
105
        return $value;
106
    }
107
108
    /**
109
     * resolving the references
110
     *
111
     * @param  mixed $name
112
     * @return mixed
113
     * @throws \RuntimeException if bad thing happens
114
     */
115
    protected function resolveReference(string $name)
116
    {
117
        if (is_string($name)) {
118
            return $this->getReference($name);
119
        }
120
        return $name;
121
    }
122
123
    /**
124
     * Dealing with unknown reference, may leave it untouched
125
     *
126
     * @param  string $subject  the subject to dereference
127
     * @param  string $matched  the matched reference
128
     * @return mixed
129
     * @throws \RuntimeException if $subject malformed
130
     */
131
    protected function resolveUnknown(string $subject, string $matched)
132
    {
133
        throw new \RuntimeException("Unable to resolve $matched in $subject");
134
    }
135
136
    /**
137
     * resolve the references
138
     *
139
     * @param  string $name
140
     * @return mixed
141
     * @throws \RuntimeException if bad thing happens
142
     */
143
    abstract protected function getReference(string $name);
144
}
145