支付宝扫一扫付款
微信扫一扫付款
(微信为保护隐私,不显示你的昵称)
PropertyAccess组件提供的是利用简单字符串标记来对一个对象或数组进行读/写的功能。
你可以通过下述两种方式安装:
通过Composer安装(Packagist上的symfony/property-access
)
通过官方Git宝库(https://github.com/symfony/property-access)
然后,包容vendor/autoload.php
文件,以开启Composer提供的自动加载机制。否则,你的程序将无法找到这个Symfony组件的类。
本组件的入口点是PropertyAccess::createPropertyAccessor
factory(工厂)。这个工厂创建的是默认配置的PropertyAccessor
实例。
1 2 3 | use Symfony\Component\PropertyAccess\PropertyAccess;
$accessor = PropertyAccess::createPropertyAccessor(); |
你可以用PropertyAccessor::getValue
方法来读取一个数组。它使用了PHP中常用的索引标记(index notation):
你可以看到,该方法返回了null
,如果索引不存在的话。
你也可以使用多维数组:
getValue()
方法非常强大,在操作对象时,你可以领教它的全部威力。
读取属性时,使用“dot(.)”标记:
1 2 3 4 5 6 7 8 9 10 11 |
访问public属性是PropertyAccess
所使用的最后一招。它尝试通过以下方法先行访问(并得到属性的值)而不是直接使用属性(来得到值)。
getValue()
方法支持使用getters进行读取。对getters使用命名约定即可创建(相应的)方法。它把属性名字驼峰化(first_name
变为FirstName
)再为其加上get
前缀。所以最终的方法变成了getFirstName
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // ...
class Person
{
private $firstName = 'Wouter';
public function getFirstName()
{
return $this->firstName;
}
}
$person = new Person();
var_dump($accessor->getValue($person, 'first_name')); // 'Wouter' |
getValue并未止步。如果没找到getter,accessor将寻找isser或hasser。这些方法的创建方式则与getters的相同,这意味着你可以做下面这样的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // ...
class Person
{
private $author = true;
private $children = array();
public function isAuthor()
{
return $this->author;
}
public function hasChildren()
{
return 0 !== count($this->children);
}
}
$person = new Person();
if ($accessor->getValue($person, 'author')) {
var_dump('He is an author');
}
if ($accessor->getValue($person, 'children')) {
var_dump('He has children');
} |
这将会得到:He is an author
。
getValue()
方法也能使用__get()
魔术方法:
最后,getValue()
方法可以使用__call()
魔术方法,但你需要通过PropertyAccessorBuilder
来开启此功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // ...
class Person
{
private $children = array(
'wouter' => array(...),
);
public function __call($name, $args)
{
$property = lcfirst(substr($name, 3));
if ('get' === substr($name, 0, 3)) {
return isset($this->children[$property])
? $this->children[$property]
: null;
} elseif ('set' === substr($name, 0, 3)) {
$value = 1 == count($args) ? $args[0] : null;
$this->children[$property] = $value;
}
}
}
$person = new Person();
// Enable magic __call 开启魔术方法 __call
$accessor = PropertyAccess::createPropertyAccessorBuilder()
->enableMagicCall()
->getPropertyAccessor();
var_dump($accessor->getValue($person, 'wouter')); // array(...) |
_call
功能默认是关闭的,若要开启它需要调用PropertyAccessorBuilder::enableMagicCall
,参见开启其他功能。
PropertyAccessor
类可以做到的不只是从数组中读取,它也能向数组写入。要实现这个需要使用PropertyAccessor::setValue
方法:
setValue()
方法有和getValue()
方法一样的功能。你可以使用setters,__set()
魔术方法,或者是属性,来设置值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // ...
class Person
{
public $firstName;
private $lastName;
private $children = array();
public function setLastName($name)
{
$this->lastName = $name;
}
public function __set($property, $value)
{
$this->$property = $value;
}
// ...
}
$person = new Person();
$accessor->setValue($person, 'firstName', 'Wouter');
$accessor->setValue($person, 'lastName', 'de Jong');
$accessor->setValue($person, 'children', array(new Person()));
var_dump($person->firstName); // 'Wouter'
var_dump($person->getLastName()); // 'de Jong'
var_dump($person->children); // array(Person()); |
若要使用__call
来设置值,你必须开启此功能,参见开启其他功能小节。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | // ...
class Person
{
private $children = array();
public function __call($name, $args)
{
$property = lcfirst(substr($name, 3));
if ('get' === substr($name, 0, 3)) {
return isset($this->children[$property])
? $this->children[$property]
: null;
} elseif ('set' === substr($name, 0, 3)) {
$value = 1 == count($args) ? $args[0] : null;
$this->children[$property] = $value;
}
}
}
$person = new Person();
// Enable magic __call
$accessor = PropertyAccess::createPropertyAccessorBuilder()
->enableMagicCall()
->getPropertyAccessor();
$accessor->setValue($person, 'wouter', array(...));
var_dump($person->getWouter()); // array(...) |
当你要检查PropertyAccessor::getValue
是否能被安全地调用而不是要真正调用该方法时,你可以使用PropertyAccessor::isReadable
来代替它:
1 2 3 4 5 | $person = new Person();
if ($accessor->isReadable($person, 'firstName')) {
// ...
} |
类似的情况是对PropertyAccessor::setValue
:调用PropertyAccessor::isWritable
方法来找到“是否有一个属性的路径可以被更新”:
1 2 3 4 5 | $person = new Person();
if ($accessor->isWritable($person, 'firstName')) {
// ...
} |
你可以混合对象和数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // ...
class Person
{
public $firstName;
private $children = array();
public function setChildren($children)
{
$this->children = $children;
}
public function getChildren()
{
return $this->children;
}
}
$person = new Person();
$accessor->setValue($person, 'children[0]', new Person);
// equal to $person->getChildren()[0] = new Person()
$accessor->setValue($person, 'children[0].firstName', 'Wouter');
// equal to $person->getChildren()[0]->firstName = 'Wouter'
var_dump('Hello '.$accessor->getValue($person, 'children[0].firstName')); // 'Wouter'
// equal to $person->getChildren()[0]->firstName |
PropertyAccessor
可以被配置成“开启额外功能”。这时你需要使用PropertyAccessorBuilder
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // ...
$accessorBuilder = PropertyAccess::createPropertyAccessorBuilder();
// Enable magic __call 开启魔术方法__call
$accessorBuilder->enableMagicCall();
// Disable magic __call 关闭魔术方法__call
$accessorBuilder->disableMagicCall();
// Check if magic __call handling is enabled
// 检查魔术方法__call功能是否开启
$accessorBuilder->isMagicCallEnabled(); // true or false
// At the end get the configured property accessor
// 最终得到配置好的property accessor
$accessor = $accessorBuilder->getPropertyAccessor();
// Or all in one 或者全部得到
$accessor = PropertyAccess::createPropertyAccessorBuilder()
->enableMagicCall()
->getPropertyAccessor(); |
或者你直接传入参数到其构造器中(此法并非推荐):
1 2 3 | // ...
$accessor = new PropertyAccessor(true); // this enables handling of magic __call
// 开启__call魔术方法 |
本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。