152 lines
2.9 KiB
PHP
152 lines
2.9 KiB
PHP
<?php
|
|
|
|
// Immutable
|
|
|
|
class Path implements IteratorAggregate {
|
|
|
|
public static function get ( $path ) {
|
|
|
|
return new self($path);
|
|
|
|
}
|
|
|
|
public static function conv ( $path ) {
|
|
|
|
if ( is_string($path) ) {
|
|
|
|
if ( !$path )
|
|
return array();
|
|
|
|
$abs = $path[0] === DIRECTORY_SEPARATOR ? array(null) : array();
|
|
$elements = array_filter(explode(DIRECTORY_SEPARATOR, $path));
|
|
return array_merge($abs, $elements);
|
|
|
|
} elseif ( is_array($path) )
|
|
return $path;
|
|
|
|
elseif ( $path instanceof self )
|
|
return $path->elements;
|
|
|
|
else throw new InvalidArgumentException();
|
|
|
|
}
|
|
|
|
private static function compute ( $elements, $target ) {
|
|
|
|
foreach ( $target as $elem )
|
|
if ( $elem === '.' );
|
|
elseif ( $elem === '..' ) {
|
|
if ( count($elements) && end($elements) && end($elements) !== '..' )
|
|
array_pop($elements);
|
|
elseif (!count($elements) || end($elements) === '..' ) $elements[] = $elem;
|
|
} elseif ( $elem || !$elements )
|
|
$elements[] = $elem;
|
|
|
|
return $elements;
|
|
|
|
}
|
|
|
|
private $elements;
|
|
|
|
public function __construct ( $path ) {
|
|
|
|
$this->elements = self::compute(array(), self::conv($path));
|
|
|
|
}
|
|
|
|
public function getIterator () {
|
|
|
|
return new ArrayIterator($this->elements);
|
|
|
|
}
|
|
|
|
public function isAbsolute () {
|
|
|
|
return count($this->elements) && !$this->elements;
|
|
|
|
}
|
|
|
|
public function append ( $path ) {
|
|
|
|
$source = $this->elements;
|
|
foreach ( func_get_args() as $path )
|
|
$source = self::compute($source, self::conv($path));
|
|
|
|
return new self($source);
|
|
|
|
}
|
|
|
|
public function pop ( $path ) {
|
|
|
|
$source = $this->elements;
|
|
$target = self::compute(array(), self::conv($path));
|
|
|
|
foreach ( func_get_args() as $path ) {
|
|
|
|
while ( count($source) && count($target) && last($source) === last($target) ) {
|
|
|
|
array_pop($source);
|
|
array_pop($target);
|
|
|
|
}
|
|
|
|
if ( count($target) )
|
|
return false;
|
|
|
|
}
|
|
|
|
return new self($source);
|
|
|
|
}
|
|
|
|
public function prepend ( $path ) {
|
|
|
|
$source = $this->elements;
|
|
foreach ( func_get_args() as $path )
|
|
$source = self::compute(self::conv($path), $source);
|
|
|
|
return new self($source);
|
|
|
|
}
|
|
|
|
public function shift ( $path ) {
|
|
|
|
$source = $this->elements;
|
|
$target = self::compute(array(), self::conv($path));
|
|
|
|
foreach ( func_get_args() as $path ) {
|
|
|
|
while ( count($source) && count($target) && reset($source) === reset($target) ) {
|
|
|
|
array_shift($source);
|
|
array_shift($target);
|
|
|
|
}
|
|
|
|
if ( count($target) )
|
|
return false;
|
|
|
|
}
|
|
|
|
return new self($source);
|
|
|
|
}
|
|
|
|
public function absolute () {
|
|
|
|
return array_key_exists(0, $this->elements) && !$this->elements[0];
|
|
|
|
}
|
|
|
|
public function __toString () {
|
|
|
|
$abs = count($this->elements) === 1 && array_key_exists(0, $this->elements) && !$this->elements[0] ? DIRECTORY_SEPARATOR : '';
|
|
|
|
return $abs . implode(DIRECTORY_SEPARATOR, $this->elements);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
?>
|