Passed
Push — main ( ba819d...a8e5ae )
by Michiel
06:08
created

PhpEvalTask::init()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
ccs 2
cts 2
cp 1
cc 1
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19
20
namespace Phing\Task\System;
21
22
use Phing\Exception\BuildException;
23
use Phing\Phing;
24
use Phing\Project;
25
use Phing\Task;
26
use Phing\Task\System\Element\LogLevelAware;
27
use Phing\Type\Parameter;
28
use Phing\Util\StringHelper;
29
30
/**
31
 * Executes PHP function or evaluates expression and sets return value to a property.
32
 *
33
 *    WARNING:
34
 *        This task can, of course, be abused with devastating effects.  E.g. do not
35
 *        modify internal Phing classes unless you know what you are doing.
36
 *
37
 * @author  Hans Lellelid <[email protected]>
38
 *
39
 * @todo Add support for evaluating expressions
40
 */
41
class PhpEvalTask extends Task
42
{
43
    use LogLevelAware;
44
45
    protected $expression; // Expression to evaluate
46
    protected $function; // Function to execute
47
    protected $class; // Class containing function to execute
48
    protected $returnProperty = null; // name of property to set to return value
49
    protected $params = []; // parameters for function calls
50
51 6
    public function init()
52
    {
53 6
        $this->logLevel = Project::MSG_INFO;
54 6
    }
55
56
    /**
57
     * Main entry point.
58
     */
59 6
    public function main()
60
    {
61 6
        if ($this->function === null && $this->expression === null) {
62
            throw new BuildException(
63
                "You must specify a function to execute or PHP expression to evalute.",
64
                $this->getLocation()
65
            );
66
        }
67
68 6
        if ($this->function !== null && $this->expression !== null) {
69
            throw new BuildException("You can specify function or expression, but not both.", $this->getLocation());
70
        }
71
72 6
        if ($this->expression !== null && !empty($this->params)) {
73
            throw new BuildException(
74
                "You cannot use nested <param> tags when evaluationg a PHP expression.",
75
                $this->getLocation()
76
            );
77
        }
78
79 6
        if ($this->function !== null) {
80 6
            $this->callFunction();
81
        } elseif ($this->expression !== null) {
82
            $this->evalExpression();
83
        }
84 6
    }
85
86
    /**
87
     * Simplifies a Parameter object of arbitrary complexity into string or
88
     * array, retaining only the value of the parameter
89
     * @param Parameter $param
90
     *
91
     * @return mixed
92
     */
93 5
    protected function simplifyParameter(Parameter $param)
94
    {
95 5
        if (empty($children = $param->getParams())) {
96 5
            return $param->getValue();
97
        }
98
99 3
        $simplified = [];
100 3
        foreach ($children as $child) {
101 3
            $simplified[] = $this->simplifyParameter($child);
102
        }
103
104 3
        return $simplified;
105
    }
106
107
    /**
108
     * Calls function and stores results in property
109
     */
110 6
    protected function callFunction()
111
    {
112 6
        if ($this->class !== null) {
113
            // import the classname & unqualify it, if necessary
114 1
            $this->class = Phing::import($this->class);
115
116 1
            $user_func = [$this->class, $this->function];
117 1
            $h_func = $this->class . '::' . $this->function; // human-readable (for log)
118
        } else {
119 5
            $user_func = $this->function;
120 5
            $h_func = $user_func; // human-readable (for log)
121
        }
122
123
        // put parameters into simple array
124 6
        $params = [];
125 6
        foreach ($this->params as $p) {
126 5
            $params[] = $this->simplifyParameter($p);
127
        }
128
129 6
        $this->log("Calling PHP function: " . $h_func . "()", $this->logLevel);
130 6
        foreach ($params as $p) {
131 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

131
            $this->log("  param: " . /** @scrutinizer ignore-type */ print_r($p, true), Project::MSG_VERBOSE);
Loading history...
132
        }
133
134 6
        $return = call_user_func_array($user_func, $params);
135
136 6
        if ($this->returnProperty !== null) {
137 6
            $this->project->setProperty($this->returnProperty, $return);
138
        }
139 6
    }
140
141
    /**
142
     * Evaluates expression and sets property to resulting value.
143
     */
144
    protected function evalExpression()
145
    {
146
        $this->log("Evaluating PHP expression: " . $this->expression, $this->logLevel);
147
        if (!StringHelper::endsWith(';', trim($this->expression))) {
148
            $this->expression .= ';';
149
        }
150
151
        if ($this->returnProperty !== null) {
152
            $retval = null;
153
            eval('$retval = ' . $this->expression);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
154
            $this->project->setProperty($this->returnProperty, $retval);
155
        } else {
156
            eval($this->expression);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
157
        }
158
    }
159
160
    /**
161
     * Set function to execute
162
     *
163
     * @param $f
164
     */
165 6
    public function setFunction($f)
166
    {
167 6
        $this->function = $f;
168 6
    }
169
170
    /**
171
     * Set [static] class which contains function to execute
172
     *
173
     * @param $c
174
     */
175 1
    public function setClass($c)
176
    {
177 1
        $this->class = $c;
178 1
    }
179
180
    /**
181
     * Sets property name to set with return value of function or expression.
182
     *
183
     * @param $r
184
     */
185 6
    public function setReturnProperty($r)
186
    {
187 6
        $this->returnProperty = $r;
188 6
    }
189
190
    /**
191
     * Set PHP expression to evaluate.
192
     *
193
     * @param $expression
194
     */
195
    public function addText($expression)
196
    {
197
        $this->expression = $expression;
198
    }
199
200
    /**
201
     * Set PHP expression to evaluate.
202
     *
203
     * @param $expression
204
     */
205
    public function setExpression($expression)
206
    {
207
        $this->expression = $expression;
208
    }
209
210
    /**
211
     * Add a nested <param> tag.
212
     */
213 5
    public function addParam(Parameter $p)
214
    {
215 5
        $this->params[] = $p;
216 5
    }
217
}
218