📄 loader.php
字号:
<?php/** * Horde YAML package * * This package is heavily inspired by the Spyc PHP YAML * implementation (http://spyc.sourceforge.net/), and portions are * copyright 2005-2006 Chris Wanstrath. * * @author Chris Wanstrath (chris@ozmm.org) * @author Chuck Hagenbuch (chuck@horde.org) * @author Mike Naberezny (mike@maintainable.com) * @license http://opensource.org/licenses/bsd-license.php BSD * @category Horde * @package Horde_Yaml *//** * Parse YAML strings into PHP data structures * * @category Horde * @package Horde_Yaml */class Horde_Yaml_Loader{ /** * List of nodes with references * @var array */ protected $_haveRefs = array(); /** * All nodes * @var array */ protected $_allNodes = array(); /** * Array of node parents * @var array */ protected $_allParent = array(); /** * Last indent level * @var integer */ protected $_lastIndent = 0; /** * Last node id * @var integer */ protected $_lastNode = null; /** * Is the parser inside a block? * @var boolean */ protected $_inBlock = false; /** * @var boolean */ protected $_isInline = false; /** * Next node id to use * @var integer */ protected $_nodeId = 1; /** * Last line number parsed. * @var integer */ protected $_lineNumber = 0; /** * Create a new YAML parser. */ public function __construct() { $base = new Horde_Yaml_Node($this->_nodeId++); $base->indent = 0; $this->_lastNode = $base->id; } /** * Return the PHP built from all YAML parsed so far. * * @return array PHP version of parsed YAML */ public function toArray() { // Here we travel through node-space and pick out references // (& and *). $this->_linkReferences(); // Build the PHP array out of node-space. return $this->_buildArray(); } /** * Parse a line of a YAML file. * * @param string $line The line of YAML to parse. * @return Horde_Yaml_Node YAML Node */ public function parse($line) { // Keep track of how many lines we've parsed for friendlier // error messages. ++$this->_lineNumber; $trimmed = trim($line); // If the line starts with a tab (instead of a space), throw a fit. if (preg_match('/^ *(\t) *[^\t ]/', $line)) { $msg = "Line {$this->_lineNumber} indent contains a tab. " . 'YAML only allows spaces for indentation.'; throw new Horde_Yaml_Exception($msg); } if (!$this->_inBlock && empty($trimmed)) { return; } elseif ($this->_inBlock && empty($trimmed)) { $last =& $this->_allNodes[$this->_lastNode]; $last->data[key($last->data)] .= "\n"; } elseif ($trimmed[0] != '#' && substr($trimmed, 0, 3) != '---') { // Create a new node and get its indent $node = new Horde_Yaml_Node($this->_nodeId++); $node->indent = $this->_getIndent($line); // Check where the node lies in the hierarchy if ($this->_lastIndent == $node->indent) { // If we're in a block, add the text to the parent's data if ($this->_inBlock) { $parent =& $this->_allNodes[$this->_lastNode]; $parent->data[key($parent->data)] .= trim($line) . $this->_blockEnd; } else { // The current node's parent is the same as the previous node's if (isset($this->_allNodes[$this->_lastNode])) { $node->parent = $this->_allNodes[$this->_lastNode]->parent; } } } elseif ($this->_lastIndent < $node->indent) { if ($this->_inBlock) { $parent =& $this->_allNodes[$this->_lastNode]; $parent->data[key($parent->data)] .= trim($line) . $this->_blockEnd; } elseif (!$this->_inBlock) { // The current node's parent is the previous node $node->parent = $this->_lastNode; // If the value of the last node's data was > or | // we need to start blocking i.e. taking in all // lines as a text value until we drop our indent. $parent =& $this->_allNodes[$node->parent]; $this->_allNodes[$node->parent]->children = true; if (is_array($parent->data)) { if (isset($parent->data[key($parent->data)])) { $chk = $parent->data[key($parent->data)]; if ($chk === '>') { $this->_inBlock = true; $this->_blockEnd = ''; $parent->data[key($parent->data)] = str_replace('>', '', $parent->data[key($parent->data)]); $parent->data[key($parent->data)] .= trim($line) . ' '; $this->_allNodes[$node->parent]->children = false; $this->_lastIndent = $node->indent; } elseif ($chk === '|') { $this->_inBlock = true; $this->_blockEnd = "\n"; $parent->data[key($parent->data)] = str_replace('|', '', $parent->data[key($parent->data)]); $parent->data[key($parent->data)] .= trim($line) . "\n"; $this->_allNodes[$node->parent]->children = false; $this->_lastIndent = $node->indent; } } } } } elseif ($this->_lastIndent > $node->indent) { // Any block we had going is dead now if ($this->_inBlock) { $this->_inBlock = false; if ($this->_blockEnd == "\n") { $last =& $this->_allNodes[$this->_lastNode]; $last->data[key($last->data)] = trim($last->data[key($last->data)]); } } // We don't know the parent of the node so we have to // find it foreach ($this->_indentSort[$node->indent] as $n) { if ($n->indent == $node->indent) { $node->parent = $n->parent; } } } if (!$this->_inBlock) { // Set these properties with information from our // current node $this->_lastIndent = $node->indent; // Set the last node $this->_lastNode = $node->id; // Parse the YAML line and return its data $node->data = $this->_parseLine($line); // Add the node to the master list $this->_allNodes[$node->id] = $node; // Add a reference to the parent list $this->_allParent[intval($node->parent)][] = $node->id; // Add a reference to the node in an indent array $this->_indentSort[$node->indent][] =& $this->_allNodes[$node->id]; // Add a reference to the node in a References array // if this node has a YAML reference in it. $is_array = is_array($node->data); $key = key($node->data); $isset = isset($node->data[$key]); if ($isset) { $nodeval = $node->data[$key]; } if (($is_array && $isset && !is_array($nodeval) && !is_object($nodeval)) && (strlen($nodeval) && (false))) { # $nodeval[0] == '&' || $nodeval[0] == '*') && $nodeval[1] != ' ')) { $this->_haveRefs[] =& $this->_allNodes[$node->id]; } elseif ($is_array && $isset && is_array($nodeval)) { // Incomplete reference making code. Needs to be // cleaned up. foreach ($node->data[$key] as $d) { if (!is_array($d) && strlen($d) && (false)) { # ($d[0] == '&' || $d[0] == '*') && $d[1] != ' ')) { $this->_haveRefs[] =& $this->_allNodes[$node->id]; } } } } } } /** * Finds and returns the indentation of a YAML line * * @param string $line A line from the YAML file * @return int Indentation level */ protected function _getIndent($line) { if (preg_match('/^\s+/', $line, $match)) { return strlen($match[0]); } else { return 0; } } /** * Parses YAML code and returns an array for a node * * @param string $line A line from the YAML file * @return array */ protected function _parseLine($line) { $array = array(); $line = trim($line); if (preg_match('/^-(.*):$/', $line)) { // It's a mapped sequence $key = trim(substr(substr($line, 1), 0, -1)); $array[$key] = ''; } elseif ($line[0] == '-' && substr($line, 0, 3) != '---') { // It's a list item but not a new stream if (strlen($line) > 1) { // Set the type of the value. Int, string, etc $array[] = $this->_toType(trim(substr($line, 1))); } else { $array[] = array(); } } elseif (preg_match('/^(.+):/', $line, $key)) { // It's a key/value pair most likely // If the key is in double quotes pull it out if (preg_match('/^(["\'](.*)["\'](\s)*:)/', $line, $matches)) { $value = trim(str_replace($matches[1], '', $line)); $key = $matches[2]; } else { // Do some guesswork as to the key and the value $explode = explode(':', $line); $key = trim(array_shift($explode)); $value = trim(implode(':', $explode)); } // Set the type of the value. Int, string, etc $value = $this->_toType($value); if (empty($key)) { $array[] = $value; } else { $array[$key] = $value; } } return $array; } /** * Finds the type of the passed value, returns the value as the new type. * * @param string $value * @return mixed */ protected function _toType($value) { // Check for PHP specials self::_unserialize($value); if (!is_scalar($value)) { return $value; } // Used in a lot of cases. $lower_value = strtolower($value); if (preg_match('/^("(.*)"|\'(.*)\')/', $value, $matches)) { $value = (string)str_replace(array('\'\'', '\\\''), "'", end($matches)); $value = str_replace('\\"', '"', $value); } elseif (preg_match('/^\\[(\s*)\\]$/', $value)) { // empty inline mapping $value = array(); } elseif (preg_match('/^\\[(.+)\\]$/', $value, $matches)) { // Inline Sequence // Take out strings sequences and mappings $explode = $this->_inlineEscape($matches[1]); // Propogate value array $value = array(); foreach ($explode as $v) { $value[] = $this->_toType($v); } } elseif (preg_match('/^\\{(\s*)\\}$/', $value)) { // empty inline mapping $value = array(); } elseif (strpos($value, ': ') !== false && !preg_match('/^{(.+)/', $value)) { // inline mapping $array = explode(': ', $value); $key = trim($array[0]); array_shift($array); $value = trim(implode(': ', $array)); $value = $this->_toType($value); $value = array($key => $value); } elseif (preg_match("/{(.+)}$/", $value, $matches)) { // Inline Mapping // Take out strings sequences and mappings $explode = $this->_inlineEscape($matches[1]); // Propogate value array $array = array(); foreach ($explode as $v) { $array = $array + $this->_toType($v); } $value = $array; } elseif ($lower_value == 'null' || $value == '' || $value == '~') { $value = null; } elseif ($lower_value == '.nan') { $value = NAN; } elseif ($lower_value == '.inf') { $value = INF; } elseif ($lower_value == '-.inf') { $value = -INF; } elseif (is_numeric($value) and !substr_count($value, ".")) { $value = (int)$value; } elseif (in_array($lower_value,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -