Completed
Push — master ( b10483...cba662 )
by Tom
02:21
created

Value::callFuncOnObject()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 3
eloc 3
nc 2
nop 3
1
<?php
2
/* @description     Transformation Style Sheets - Revolutionising PHP templating    *
3
 * @author          Tom Butler [email protected]                                             *
4
 * @copyright       2015 Tom Butler <[email protected]> | https://r.je/                      *
5
 * @license         http://www.opensource.org/licenses/bsd-license.php  BSD License *
6
 * @version         1.0                                                             */
7
namespace Transphporm\Parser;
8
/** Parses "string" and function(args) e.g. data(foo) or iteration(bar) */ 
9
class Value {
10
	private $dataFunction;
11
	private $callParamsAsArray;
12
	private $parent;
13
14
	public function __construct($dataFunction, Value $parent = null, $callParamsAsArray = true) {
15
		$this->dataFunction = $dataFunction;
16
		$this->callParamsAsArray = $callParamsAsArray;
17
		$this->parent = $parent;
18
	}
19
20
	private function extractQuotedString($marker, $str) {
21
		$finalPos = $this->findMatchingPos($str, $marker);
22
		$string = substr($str, 1, $finalPos-1);
23
		//Now remove escape characters
24
		return str_replace('\\' . $marker, $marker, $string);
25
	}
26
27
	private function parseFunction($function) {
28
		$open = strpos($function, '(');
29
		if ($open) {
30
			$name = substr($function, 0, $open);
31
			$bracketMatcher = new BracketMatcher($function);
32
			$params = $bracketMatcher->match('(', ')');
33
			
34
			return ['name' => $name, 'params' => $params, 'endPoint' => $bracketMatcher->getClosePos()];
35
		}
36
		else return ['name' => null, 'params' => $function, 'endPoint' => strlen($function)];
37
	}
38
39
	public function parse($function, \DomElement $element) {
40
		$result = [];
41
		if ($function && in_array($function[0], ['\'', '"'])) {
42
			$finalPos = $this->findMatchingPos($function, $function[0]);
43
			$result[] = $this->extractQuotedString($function[0], $function);
44
		}
45
		else {
46
			$func = $this->parseFunction($function);
47
			$finalPos = $func['endPoint'];			
48
49
			if (($data = $this->getFunctionValue($func['name'], $func['params'], $element)) !== false) $result = $this->appendToArray($result, $data);
50
			else $result[] = trim($function);
51
		}
52
		$remaining = trim(substr($function, $finalPos+1));
53
		return $this->parseNextValue($remaining, $result, $element);
54
	}
55
56
	private function getFunctionValue($name, $params, $element) {
57
		if (($data = $this->callFunc($name, $params, $element)) !== false) {
58
			return $data;
59
		}
60
		else if ($this->parent != null && ($data = $this->parent->callFunc($name, $params, $element)) !== false) {
61
			return $data;
62
		}
63
		else return false;
64
	}
65
66
	private function appendToArray($array, $value) {
67
		if (is_array($value)) $array += $value;
68
		else $array[] = $value;
69
		return $array;
70
	}
71
72
	private function callFunc($name, $params, $element) {
73
		if ($name && $this->isCallable($this->dataFunction, $name)) {
74
			if ($this->callParamsAsArray) return $this->dataFunction->$name($this->parse($params, $element), $element);	
75
			else {
76
				return $this->callFuncOnObject($this->dataFunction, $name, $this->parse($params, $element));
77
			}
78
		}
79
		return false;
80
	}
81
82
	//is_callable does not detect closures on properties, only methods defined in the class!
83
	private function isCallable($obj, $func) {
84
		return (isset($obj->$func) && is_callable($obj->$func)) || is_callable([$obj, $func]);
85
	}
86
87
	private function callFuncOnObject($obj, $func, $params) {
88
		if (isset($obj->$func) && is_callable($obj->$func)) return call_user_func_array($obj->$func, $params);
89
		else return call_user_func_array($obj, $params);
90
	}
91
92
	private function parseNextValue($remaining, $result, $element) {
93
		if (strlen($remaining) > 0 && $remaining[0] == ',') $result = array_merge($result, $this->parse(trim(substr($remaining, 1)), $element));
94
		return $result;
95
	}
96
	
97
	private function findMatchingPos($string, $char, $start = 0, $escape = '\\') {
98
		$pos = $start+1;
99
		$end = 0;
0 ignored issues
show
Unused Code introduced by
$end is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
100
		while ($end = strpos($string, $char, $pos)) {
101
			if ($string[$end-1] === $escape) $pos = $end+1;
102
			else {
103
				break;
104
			}
105
		}
106
		return $end;
107
	}
108
}