mschop/pathogen

通用的PHP路径库。

0.7.1 2022-02-21 19:04 UTC

README

通用的PHP路径库。

Build Status

未来开发

此包是已废弃的包 eloquent/pathogen 的分支。我将继续在这个库上工作。请随时提出功能请求或错误报告。

安装和文档

什么是 Pathogen?

Pathogen 是一个用于路径操作的库。 Pathogen 支持文件系统路径,包括 Unix 和 Windows 风格的路径,但它实际上是一个通用路径实现,能够表示 URI 路径和其他类似结构,同时提供全面的 API。

目录

Pathogen 概念

路径部分

Pathogen 路径的整体结构可以分解为更小的部分。此图显示了这些命名部分如何应用于典型路径

  A   A   ___ A ___
 / \ / \ /         \
/foo/bar/baz.qux.pop
         \_________/
            name
\__________________/
        path

A = atom

‘名称’部分可以进一步分解如下

  NWE    E
/     \ / \
baz.qux.pop
\_/ \_____/
 NP   NS

NWE = name without extension
  E = extension
 NP = name prefix
 NS = name suffix

路径原子

Pathogen 中,路径由一系列 '原子' 组成。原子是路径层次结构中的各个部分。给定路径 /path/to/foo,原子序列将是 pathtofoo。斜杠字符被称为 '分隔符'。

原子 ...Pathogen 中具有特殊意义。单个点 (.) 被称为 '自我原子',通常用于引用当前路径。双点 (..) 被称为 '父原子',用于引用当前路径之上的路径。熟悉典型文件系统路径的人应该已经熟悉它们的行为。

给定一个路径实例,路径的原子可以按以下方式确定

$atoms = $path->atoms(); // returns an array of strings

路径名称

路径的 '名称' 部分仅仅是路径的最后一个原子。如果路径没有原子,则其名称为空字符串。给定一个路径实例,路径的名称可以这样确定

$name = $path->name(); // returns a string

路径名称扩展

路径的名称可以进一步使用扩展分隔符 (.) 来分割。例如,给定路径名称 foo.bar.bazPathogen 可以确定 '无扩展名称' (foo.bar)、'名称前缀' (foo)、'名称后缀' (bar.baz) 和 '扩展名' (baz)。

给定一个路径实例,可以按以下方式检索各个部分

$nameWithoutExtension = $path->nameWithoutExtension(); // returns a string
$namePrefix = $path->namePrefix(); // returns a string
$nameSuffix = $path->nameSuffix(); // returns a string or null
$extension = $path->extension(); // returns a string or null

尾部分隔符

Pathogen 能够表示带有尾部分隔符的路径 (/)。这在某些逻辑中尾部分隔符具有特殊意义的情况下很有用,例如 Unix cp 命令的行为。尾部分隔符支持完全是出于开发者使用 Pathogen 的目的;它不影响 Pathogen 本身使用的任何逻辑。

值得注意的是,由Pathogen生成的所有新路径实例都会去除末尾的反斜杠,除非明确指出否则。

绝对和相对路径

Pathogen中,绝对路径和相对路径由两个不同的类表示。虽然这两个类都实现了共同的PathInterface接口,但其他方法分别由AbsolutePathInterfaceRelativePathInterface提供。

这种区分提供了诸多好处,其中之一就是能够利用PHP的类型提示来限制所需路径的类型。

use Eloquent\Pathogen\AbsolutePathInterface;
use Eloquent\Pathogen\PathInterface;
use Eloquent\Pathogen\RelativePathInterface;

function anyPath(PathInterface $path)
{
    // accepts any path
}

function absoluteOnly(AbsolutePathInterface $path)
{
    // accepts only absolute paths
}

function relativeOnly(RelativePathInterface $path)
{
    // accepts only relative paths
}

特殊路径

'root'路径被认为是最高级的绝对路径,表示为一个单独的分隔符,没有原子(/)。

'self'路径被认为是指向'当前'路径的,表示为一个单独的self原子(.)。

创建路径

静态工厂方法

创建Pathogen路径的最简单方法是使用静态工厂方法。为了有效地使用此方法,只需选择最合适的类以匹配路径类型即可。

use Eloquent\Pathogen\AbsolutePath;
use Eloquent\Pathogen\FileSystem\FileSystemPath;
use Eloquent\Pathogen\Path;
use Eloquent\Pathogen\RelativePath;
use Eloquent\Pathogen\Unix\UnixPath;
use Eloquent\Pathogen\Windows\AbsoluteWindowsPath;
use Eloquent\Pathogen\Windows\WindowsPath;

$path = Path::fromString('/path/to/foo'); // absolute path
$path = Path::fromString('bar/baz');      // relative path

$path = AbsolutePath::fromString('/path/to/foo'); // only creates absolute paths
$path = RelativePath::fromString('bar/baz');      // only creates relative paths

$path = FileSystemPath::fromString('/path/to/foo');   // Unix path
$path = FileSystemPath::fromString('C:\path\to\foo'); // Windows path

$path = UnixPath::fromString('/path/to/foo');      // only creates Unix paths
$path = WindowsPath::fromString('C:\path\to\foo'); // only creates Windows paths

$path = AbsoluteWindowsPath::fromString('C:\path\to\foo'); // only creates absolute Windows paths

除了fromString()方法之外,还有其他工厂方法,其中一些对所有路径都是通用的,而另一些则更专业化。

use Eloquent\Pathogen\Path;
use Eloquent\Pathogen\Windows\AbsoluteWindowsPath;

// Equivalent to '/path/to/foo'
$path = Path::fromAtoms(array('path', 'to', 'foo'));

// Equivalent to 'C:\path\to\foo'
$path = AbsoluteWindowsPath::fromDriveAndAtoms(array('path', 'to', 'foo'), 'C');

工厂对象

Pathogen提供了用于创建路径的工厂类。所有路径工厂都实现了PathFactoryInterface接口,允许从各种类型的输入中创建路径。

路径工厂使用的一个简单示例如下:

use Eloquent\Pathogen\FileSystem\Factory\FileSystemPathFactory;

$factory = new FileSystemPathFactory;

$pathFoo = $factory->create('/path/to/foo');
$pathBar = $factory->create('C:/path/to/bar');

路径解析

路径解析涉及获取一个可能为相对路径或绝对路径的路径,并确定在给定的已知'基础'路径下该路径指向的位置。路径解析的结果始终是绝对路径。

例如,考虑当前路径为/path/to/foo。相对路径bar/baz将解析为相对于此路径的/path/to/foo/bar/baz。相反,绝对路径/path/to/qux在解析后不会改变,因为它已经是绝对路径。

解析方法

使用Pathogen实现路径解析的最简单方法是使用路径上的最合适的方法。

use Eloquent\Pathogen\FileSystem\FileSystemPath;

$basePath = FileSystemPath::fromString('/path/to/foo');
$relativePath = FileSystemPath::fromString('bar/baz');
$absolutePath = FileSystemPath::fromString('/path/to/qux');

echo $basePath->resolve($relativePath); // outputs '/path/to/foo/bar/baz'
echo $basePath->resolve($absolutePath); // outputs '/path/to/qux'

echo $relativePath->resolveAgainst($basePath); // outputs '/path/to/foo/bar/baz'

解析器对象

路径解析器也是Pathogen中的独立概念。以下是一个使用示例的简单示例。

use Eloquent\Pathogen\FileSystem\FileSystemPath;
use Eloquent\Pathogen\Resolver\PathResolver;

$resolver = new PathResolver;

$basePath = FileSystemPath::fromString('/path/to/foo');
$relativePath = FileSystemPath::fromString('bar/baz');
$absolutePath = FileSystemPath::fromString('/path/to/qux');

echo $resolver->resolve($basePath, $relativePath); // outputs '/path/to/foo/bar/baz'
echo $resolver->resolve($basePath, $absolutePath); // outputs '/path/to/qux'

路径归一化

路径规范化是将路径转换为最简或规范形式的过程。这意味着尽可能多地解析self和父原子。例如,路径/path/to/foo/../bar规范化为/path/to/bar

规范化对绝对路径和相对路径的工作方式不同。绝对路径总是可以解析为没有self或父原子的规范形式。相对路径通常可以简化,但仍可能包含这些特殊原子。例如,路径../foo/../..实际上将规范化为../..

请注意,对于绝对路径,根路径(/)是父原子将规范化的最高级路径。也就是说,具有比常规原子更多的父原子的路径,如/../../../foo/../..都将规范化为根路径(/)。

Pathogen中,除非需要用于计算或通过API手动进行,否则通常不会进行路径规范化。如果需要某种原因的规范化路径,则由开发人员处理。

归一化方法

规范化路径的最简单方法是使用normalize()方法。

use Eloquent\Pathogen\FileSystem\FileSystemPath;

$path = FileSystemPath::fromString('/path/./to/foo/../bar');

echo $path->normalize(); // outputs '/path/to/bar'

归一化器对象

路径规范化器也是Pathogen中的独立概念。以下是一个使用示例的简单示例。

use Eloquent\Pathogen\FileSystem\FileSystemPath;
use Eloquent\Pathogen\FileSystem\Normalizer\FileSystemPathNormalizer;

$normalizer = new FileSystemPathNormalizer;

$path = FileSystemPath::fromString('/path/./to/foo/../bar');

echo $normalizer->normalize($path); // outputs '/path/to/bar'

文件系统路径

Pathogen平台无关的方式提供处理文件系统路径的支持。根据情况,Pathogen支持两种方法。

第一种方法是对路径字符串进行检查,并根据“最佳猜测”创建适当的路径实例。这由FileSystemPath类处理

use Eloquent\Pathogen\FileSystem\FileSystemPath;

$pathFoo = FileSystemPath::fromString('/path/to/foo');   // creates a Unix-style path
$pathBar = FileSystemPath::fromString('C:/path/to/bar'); // creates a Windows path

第二种方法是根据代码运行的当前平台创建路径。也就是说,当在Linux或Unix上运行时,创建Unix风格的路径,当在Windows上运行时,创建Windows路径。这由PlatformFileSystemPath类处理

use Eloquent\Pathogen\FileSystem\PlatformFileSystemPath;

// creates a path to match the current platform
$path = PlatformFileSystemPath::fromString('/path/to/foo');

请注意,FileSystemPathPlatformFileSystemPath类仅是具有静态方法的工具类。实际使用的路径类将取决于输入。如果需要对文件系统路径进行类型提示,应使用FileSystemPathInterface或其更专业的子接口。

路径不可变性

Pathogen中的路径是不可变的,这意味着一旦创建,就不能修改。当对路径执行某些修改操作,如规范化或解析时,会生成一个新的路径实例,而不是修改原始实例。这允许将路径作为接口的一部分暴露,而不会创建漏斗抽象。

Windows 路径支持

Pathogen提供了对Windows路径的支持。除了Unix风格路径的方法外,Windows路径还包含一个可选的驱动器指定符。驱动器指定符可以通过drive()方法获得。

$drive = $path->drive(); // returns a single-character string, or null

依赖消费者特性

Pathogen提供了一些特质,使得针对PHP 5.4及以上版本的代码使用其服务变得极其简单。

依赖消费者特质的理念很简单。如果一个类需要,例如,一个路径工厂,它可以简单地使用一个PathFactoryTrait。这会给类添加setPathFactory()pathFactory()方法,用于管理路径工厂依赖。

此示例演示了如何使用文件系统路径工厂特质

use Eloquent\Pathogen\FileSystem\Factory\Consumer\FileSystemPathFactoryTrait;

class ExampleConsumer
{
    use FileSystemPathFactoryTrait;
}

$consumer = new ExampleConsumer;
echo get_class($consumer->pathFactory()); // outputs 'Eloquent\Pathogen\FileSystem\Factory\FileSystemPathFactory'

可用的依赖消费者特性

使用示例

将用户提供的路径解析为当前工作目录

use Eloquent\Pathogen\FileSystem\Factory\PlatformFileSystemPathFactory;

$factory = new PlatformFileSystemPathFactory;
$workingDirectoryPath = $factory->createWorkingDirectoryPath();

$path = $workingDirectoryPath->resolve(
    $factory->create($_SERVER['argv'][1])
);

解析一个路径与另一个任意路径

use Eloquent\Pathogen\Path;

$basePath = Path::fromString('/path/to/base');
$path = Path::fromString('../child');

$resolvedPath = $basePath->resolve($path);

echo $resolvedPath->string();              // outputs '/path/to/base/../child'
echo $resolvedPath->normalize()->string(); // outputs '/path/to/child'

确定一个路径是否包含在另一个路径内部

use Eloquent\Pathogen\Path;

$basePath = Path::fromString('/path/to/foo');
$pathA = Path::fromString('/path/to/foo/bar');
$pathB = Path::fromString('/path/to/somewhere/else');

var_dump($basePath->isAncestorOf($pathA)); // outputs 'bool(true)'
var_dump($basePath->isAncestorOf($pathB)); // outputs 'bool(false)'

将扩展名附加到路径

use Eloquent\Pathogen\Path;

$path = Path::fromString('/path/to/foo.bar');
$pathWithExtension = $path->joinExtensions('baz');

echo $pathWithExtension->string(); // outputs '/path/to/foo.bar.baz'

替换路径的扩展名

use Eloquent\Pathogen\Path;

$path = Path::fromString('/path/to/foo.bar');
$pathWithNewExtension = $path->replaceExtension('baz');

echo $pathWithNewExtension->string(); // outputs '/path/to/foo.baz'

替换路径的一部分

use Eloquent\Pathogen\Path;

$path = Path::fromString('/path/to/foo/bar');
$pathWithReplacement = $path->replace(1, array('for', 'baz'), 2);

echo $pathWithReplacement->string(); // outputs '/path/for/baz/bar'