Faker 是一个虚拟数据的生成器,可以用它填充数据库进行压力测试或者创建优雅的 XML 文档。安装如果项目支持 composer ,使用以下命令安装。不支持请到 Faker 的 Github 仓库下载源码,放入项目的扩展包文件夹中。composer require fzaninotto/faker为了演示功能,我使用以下命令创建了一个新项目:// 创建新项目文件夹mkdir data-seedercd data-seeder// 安装 faker 扩展composer require fzaninotto/faker基本使用方法在根目录下创建测试文件 test.php,输入以下代码:<?phprequire_once DIR . ‘/vendor/fzaninotto/faker/src/autoload.php’;$faker = Faker\Factory::create();echo $faker->name, “\n”;echo $faker->address, “\n”;echo $faker->text;在 CLI 模式下运行脚本, php test.php 查看输出结果。faker 的结果是随机生成的:Prof. Kailyn Barton9230 Herzog Groves Suite 005Gusikowskihaven, CO 60533-4716Nesciunt voluptas debitis iusto consectetur possimus mollitia in quam. Vel non rem temporibus illo numquam est. Sit fugit sed fugit id eligendi eaque sunt possimus.faker 的专有名词faker 中定义了一些专有名词帮助我们理解它的设计思路,明白这些概念对理解他的源码非常有帮助。格式器(formatters)除了以上三个属性,faker 还提供了大量可供选择的模拟数据。每个生成器属性(例如上面使用的 name,address 和 lorem)都被叫做 格式器(formatters)。提供器(providers)我们需要填充的数据有很多种类,例如基本的随机数据:整数、浮点数、字母随机的人物信息:姓名、姓、名 等随机的号码:手机号、电话号Faker 将每种分类定义为 provider,查看 data-seeder/vendor/fzaninotto/faker/src/Faker/Provider 可以看到各种 provider 的类文件,以及分语言包的文件。源码解析faker 扩展包体积虽小,五脏俱全,非常有学习价值。faker 对象生成查看 faker 生成器的工厂方法:const DEFAULT_LOCALE = ’en_US’;protected static $defaultProviders = array(‘Address’, ‘Barcode’, ‘Biased’, ‘Color’, ‘Company’, ‘DateTime’, ‘File’, ‘HtmlLorem’, ‘Image’, ‘Internet’, ‘Lorem’, ‘Miscellaneous’, ‘Payment’, ‘Person’, ‘PhoneNumber’, ‘Text’, ‘UserAgent’, ‘Uuid’);public static function create($locale = self::DEFAULT_LOCALE){ $generator = new Generator(); foreach (static::$defaultProviders as $provider) { $providerClassName = self::getProviderClassname($provider, $locale); $generator->addProvider(new $providerClassName($generator)); } return $generator;}参数 locale 是语言包,默认为 en_US 美国英语。在 data-seeder/vendor/fzaninotto/faker/src/Faker/Provider 目录中可以查看所有支持的语言包。默认的 providers(provider 已经在上面提到过),在以上 Provider 目录中可以一一对应的找到。循环数组,将对应的 provider 添加到生成器 $generator。getProviderClassnameprotected static function getProviderClassname($provider, $locale = ‘’){ if ($providerClass = self::findProviderClassname($provider, $locale)) { return $providerClass; } // fallback to default locale if ($providerClass = self::findProviderClassname($provider, static::DEFAULT_LOCALE)) { return $providerClass; } // fallback to no locale if ($providerClass = self::findProviderClassname($provider)) { return $providerClass; } throw new \InvalidArgumentException(sprintf(‘Unable to find provider “%s” with locale “%s”’, $provider, $locale));}getProviderClassname 将按照以下逻辑寻找 provider 类,如果不存在于当前文件就到下一级文件查找,找不到就会跑出异常:用户传入的语言包文件夹 -> 默认的en_US语言包文件夹 -> Provider根目录addProviderpublic function addProvider($provider){ array_unshift($this->providers, $provider);}addProvider 就非常简单了,只是把找到的 provider 加入数组头部,数组存储在将要返回的 $generator 对象的属性中。faker 对象调用在使用 faker 返回的对象时,有两种方式:调用属性和调用方法。这些调用都会触发魔术方法:public function format($formatter, $arguments = array()){ return call_user_func_array($this->getFormatter($formatter), $arguments);}public function __get($attribute){ return $this->format($attribute);}public function __call($method, $attributes){ return $this->format($method, $attributes);}两者逻辑类似,这里说明相对麻烦一点的 __call 魔术方法,魔术方法会将调用的方法名和参数传入 farmat 方法。getFormatterpublic function getFormatter($formatter){ if (isset($this->formatters[$formatter])) { return $this->formatters[$formatter]; } foreach ($this->providers as $provider) { if (method_exists($provider, $formatter)) { $this->formatters[$formatter] = array($provider, $formatter); return $this->formatters[$formatter]; } } throw new \InvalidArgumentException(sprintf(‘Unknown formatter “%s”’, $formatter));}$this->formatters 中存储的就是 faker 专有名词那里提到的 formatter(格式器)相关的信息。为了方便理解,这里以获得数组中一个随机元素为例,说明这些抽象的概念。$faker->randomElement([‘a’, ‘b’, ‘c’]);当调用此方法时,触发魔术方法,然后遍历每一个 provider 类,查找是否存在此方法。直到在 Base.php 中发现存在此方法,此时要使用的提供器 provider 为 Base.php,格式器 formatter 就是 randomElement() 方法。然后就需要将 Base 中存在 randomeElement() 的对应关系存储起来,避免下次重新遍历所有 provider,这就是 $this->formatters 实现的原因。此方法返回对应的 provider 和 formatters 后,通过 call_user_func_array 调用并返回结果。至此,一个完整的 faker 对象生成和调用的过程就结束了。