Passed
Push — main ( 7acf43...7c92cb )
by Michiel
06:10
created

PhpEvalTask   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 171
Duplicated Lines 0 %

Test Coverage

Coverage 61.9%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 27
eloc 59
c 1
b 1
f 0
dl 0
loc 171
ccs 39
cts 63
cp 0.619
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A setExpression() 0 3 1
A addText() 0 3 1
A evalExpression() 0 13 3
A init() 0 3 1
A simplifyParameter() 0 12 3
A setClass() 0 3 1
A setReturnProperty() 0 3 1
A callFunction() 0 28 5
A setFunction() 0 3 1
A addParam() 0 3 1
B main() 0 24 9
1
<?php
2
3
/**
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the LGPL. For more information please see
18
 * <http://phing.info>.
19
 */
20
21
namespace Phing\Task\System;
22
23
use Phing\Exception\BuildException;
24
use Phing\Phing;
25
use Phing\Project;
26
use Phing\Task;
27
use Phing\Task\System\Element\LogLevelAware;
28
use Phing\Type\Parameter;
29
use Phing\Util\StringHelper;
30
31
/**
32
 * Executes PHP function or evaluates expression and sets return value to a property.
33
 *
34
 *    WARNING:
35
 *        This task can, of course, be abused with devastating effects.  E.g. do not
36
 *        modify internal Phing classes unless you know what you are doing.
37
 *
38
 * @author  Hans Lellelid <[email protected]>
39
 *
40
 * @todo Add support for evaluating expressions
41
 */
42
class PhpEvalTask extends Task
43
{
44
    use LogLevelAware;
45
46
    protected $expression; // Expression to evaluate
47
    protected $function; // Function to execute
48
    protected $class; // Class containing function to execute
49
    protected $returnProperty; // name of property to set to return value
50
    protected $params = []; // parameters for function calls
51
52 6
    public function init()
53
    {
54 6
        $this->logLevel = Project::MSG_INFO;
55
    }
56
57
    /**
58
     * Main entry point.
59
     */
60 6
    public function main()
61
    {
62 6
        if (null === $this->function && null === $this->expression) {
63
            throw new BuildException(
64
                'You must specify a function to execute or PHP expression to evalute.',
65
                $this->getLocation()
66
            );
67
        }
68
69 6
        if (null !== $this->function && null !== $this->expression) {
70
            throw new BuildException('You can specify function or expression, but not both.', $this->getLocation());
71
        }
72
73 6
        if (null !== $this->expression && !empty($this->params)) {
74
            throw new BuildException(
75
                'You cannot use nested <param> tags when evaluationg a PHP expression.',
76
                $this->getLocation()
77
            );
78
        }
79
80 6
        if (null !== $this->function) {
81 6
            $this->callFunction();
82
        } elseif (null !== $this->expression) {
83
            $this->evalExpression();
84
        }
85
    }
86
87
    /**
88
     * Set function to execute.
89
     *
90
     * @param string $function
91
     */
92 6
    public function setFunction($function)
93
    {
94 6
        $this->function = $function;
95
    }
96
97
    /**
98
     * Set [static] class which contains function to execute.
99
     *
100
     * @param string $class
101
     */
102 1
    public function setClass($class)
103
    {
104 1
        $this->class = $class;
105
    }
106
107
    /**
108
     * Sets property name to set with return value of function or expression.
109
     *
110
     * @param string $returnProperty
111
     */
112 6
    public function setReturnProperty($returnProperty)
113
    {
114 6
        $this->returnProperty = $returnProperty;
115
    }
116
117
    /**
118
     * Set PHP expression to evaluate.
119
     *
120
     * @param string $expression
121
     */
122
    public function addText($expression)
123
    {
124
        $this->expression = $expression;
125
    }
126
127
    /**
128
     * Set PHP expression to evaluate.
129
     *
130
     * @param string $expression
131
     */
132
    public function setExpression($expression)
133
    {
134
        $this->expression = $expression;
135
    }
136
137
    /**
138
     * Add a nested <param> tag.
139
     */
140 5
    public function addParam(Parameter $p)
141
    {
142 5
        $this->params[] = $p;
143
    }
144
145
    /**
146
     * Simplifies a Parameter object of arbitrary complexity into string or
147
     * array, retaining only the value of the parameter.
148
     */
149 5
    protected function simplifyParameter(Parameter $param)
150
    {
151 5
        if (empty($children = $param->getParams())) {
152 5
            return $param->getValue();
153
        }
154
155 3
        $simplified = [];
156 3
        foreach ($children as $child) {
157 3
            $simplified[] = $this->simplifyParameter($child);
158
        }
159
160 3
        return $simplified;
161
    }
162
163
    /**
164
     * Calls function and stores results in property.
165
     */
166 6
    protected function callFunction()
167
    {
168 6
        if (null !== $this->class) {
169
            // import the classname & unqualify it, if necessary
170 1
            $this->class = Phing::import($this->class);
171
172 1
            $user_func = [$this->class, $this->function];
173 1
            $h_func = $this->class . '::' . $this->function; // human-readable (for log)
174
        } else {
175 5
            $user_func = $this->function;
176 5
            $h_func = $user_func; // human-readable (for log)
177
        }
178
179
        // put parameters into simple array
180 6
        $params = [];
181 6
        foreach ($this->params as $p) {
182 5
            $params[] = $this->simplifyParameter($p);
183
        }
184
185 6
        $this->log('Calling PHP function: ' . $h_func . '()', $this->logLevel);
186 6
        foreach ($params as $p) {
187 5
            $this->log('  param: ' . print_r($p, true), Project::MSG_VERBOSE);
0 ignored issues
show
Bug introduced by
Are you sure print_r($p, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

187
            $this->log('  param: ' . /** @scrutinizer ignore-type */ print_r($p, true), Project::MSG_VERBOSE);
Loading history...
188
        }
189
190 6
        $return = call_user_func_array($user_func, $params);
191
192 6
        if (null !== $this->returnProperty) {
193 6
            $this->project->setProperty($this->returnProperty, $return);
194
        }
195
    }
196
197
    /**
198
     * Evaluates expression and sets property to resulting value.
199
     */
200
    protected function evalExpression()
201
    {
202
        $this->log('Evaluating PHP expression: ' . $this->expression, $this->logLevel);
203
        if (!StringHelper::endsWith(';', trim($this->expression))) {
204
            $this->expression .= ';';
205
        }
206
207
        if (null !== $this->returnProperty) {
208
            $retval = null;
209
            eval('$retval = ' . $this->expression);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
210
            $this->project->setProperty($this->returnProperty, $retval);
211
        } else {
212
            eval($this->expression);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
213
        }
214
    }
215
}
216