In PHP, arrays can be said to be a very powerful type of data structure. We can even say that arrays in PHP are the soul of PHP, and it is not an exaggeration to say so. Compared with static languages such as Java, PHP arrays have no length limit, no key value type limit, which is very flexible and convenient. Array is a basic structure type. It is at the same level as Int and String. What we are going to learn today is the concept of operating objects as arrays. Let's learn how to use them first, and finally talk about the use of doing so.
Object array
The object array corresponds to the ArrayObject class. If you want your class to become this kind of object array, then you can directly inherit this ArrayObject. Its use is very simple. The main difference between it and an array is that it is a real object, not a basic data structure. In other words, for is_object() and is_array(), their results will be different. Moreover, array operations are implemented through external public functions, while the ArrayObject object has some internal methods. Of course, you can inherit it and extend it yourself to implement more methods.
Convert directly from array to object array
When we instantiate ArrayObject, we can directly pass an array as a construction parameter, then the content of the object array is based on the passed-in array.
$ao = new ArrayObject(['a' => 'one', 'b' => 'two', 'c' => 'three']);
var_dump($ao);
// object(ArrayObject)#1 (1) {
// ["storage":"ArrayObject":private]=>
// array(3) {
// ["a"]=>
// string(3) "one"
// ["b"]=>
// string(3) "two"
// ["c"]=>
// string(5) "three"
// }
// }
foreach ($ao as $k => $element) {
echo $k, ': ', $element, PHP_EOL;
}
// a: one
// b: two
// c: three
The object array implements related interfaces such as iterators, so it can be traversed through foreach().
Instantiate an array of objects and assign values
In addition to directly passing a construction parameter, we can also instantiate an empty object array, and then manipulate it like a normal array.
$ao = new ArrayObject();
$ao->a = 'one';
$ao['b'] = 'two';
$ao->append('three');
var_dump($ao);
// object(ArrayObject)#3 (2) {
// ["a"]=>
// string(3) "one"
// ["storage":"ArrayObject":private]=>
// array(2) {
// ["b"]=>
// string(3) "two"
// [0]=>
// string(5) "three"
// }
// }
foreach ($ao as $k => $element) {
echo $k, ': ', $element, PHP_EOL; // two three
}
// b: two
// 0: three
We can manipulate this object in the form of array subscripts. This is because ArrayObject also implements the ArrayAccess interface. About this interface, our previous article also talked about how PHP traverses objects? https://mp.weixin.qq.com/s/cFMI0PZk2Zi4_O0FlZhdNg . One thing to note here is that if the operation is performed in the manner of an object's attribute, this attribute is not an iterable content. As can be seen from this paragraph and the above test code, the contents of the array are stored in a storage property, and the a property we directly manipulate is equal to the storage property. In fact, we can guess from here that ArrayObject actually manipulates the contents of the array stored in this storage through the implementation of the ArrayAccess interface. In addition, the append() method is the method of adding data to ArrayObject, which by default appends the contents of the array in the form of a number subscript.
In summary, in the final traversal, we only printed out the contents of the two subscripts b and 0. Because a is a property of the object, it is not in the storage array maintained by it.
We can set a mark, which is actually an attribute parameter, to make this attribute assignment the same operation as array assignment, that is, make the above a attribute operation into an array assignment.
$ao->setFlags(ArrayObject::ARRAY_AS_PROPS);
$ao->d = 'four';
var_dump($ao);
// object(ArrayObject)#3 (2) {
// ["a"]=>
// string(3) "one"
// ["storage":"ArrayObject":private]=>
// array(3) {
// ["b"]=>
// string(3) "two"
// [0]=>
// string(5) "three"
// ["d"]=>
// string(4) "four"
// }
// }
foreach ($ao as $k => $element) {
echo $k, ': ', $element, PHP_EOL; // two three
}
// b: two
// 0: three
// d: four
After setting ArrayObject::ARRAY_AS_PROPS through the setFlags() method, we can see that the d attribute operation directly enters the storage, that is, this attribute operation becomes an array operation.
Offset subscript operation
Like other data structures, the object array also has a series of cursor offset subscript operations, in fact, it is through several functions to manipulate subscript data.
var_dump($ao->offsetExists('b')); // bool(true)
var_dump($ao->offsetGet('b')); // string(3) "two"
$ao->offsetSet('b', 'new two');
var_dump($ao->offsetGet('b')); // string(7) "new two"
$ao->offsetSet('e', 'five');
var_dump($ao->offsetGet('e')); // string(4) "five"
$ao->offsetUnset('e');
var_dump($ao->offsetGet('e')); // NULL
var_dump($ao->offsetExists('e')); // bool(false)
The operations here are similar to those in other data structures, so I won't explain more.
Sort
For ordinary arrays, if we need sorting operations, we need to use ordinary array-related functions, such as sort() or ksort(). The object array itself is actually an object, which means that it cannot be used in these ordinary array functions. Interested friends can use the sort(), array_map() functions to try to operate the ArrayObject object. Therefore, the ArrayObject object comes with some data manipulation functions, but they are not very comprehensive, that is, just a few sort-related operations.
$ao->asort();
var_dump($ao);
// object(ArrayObject)#3 (2) {
// ["a"]=>
// string(3) "one"
// ["storage":"ArrayObject":private]=>
// array(3) {
// ["d"]=>
// string(4) "four"
// ["b"]=>
// string(7) "new two"
// [0]=>
// string(5) "three"
// }
// }
$ao->ksort();
var_dump($ao);
// object(ArrayObject)#3 (2) {
// ["a"]=>
// string(3) "one"
// ["storage":"ArrayObject":private]=>
// array(3) {
// [0]=>
// string(5) "three"
// ["b"]=>
// string(7) "new two"
// ["d"]=>
// string(4) "four"
// }
// }
Of course, there are corresponding sorting functions of usort(), uksort(), natsort(), and natcasesort().
Toggle the contents of the array
For object arrays, the data content is either assigned like an array or passed in through construction parameters during initialization. In fact, there is a method function that can directly replace all the data content in ArrayObject.
$ao->exchangeArray(['a' => 'one', 'b' => 'two', 'c' => 'three', 'd' => 4, 0 => 'a']);
var_dump($ao);
// object(ArrayObject)#3 (2) {
// ["a"]=>
// string(3) "one"
// ["storage":"ArrayObject":private]=>
// array(5) {
// ["a"]=>
// string(3) "one"
// ["b"]=>
// string(3) "two"
// ["c"]=>
// string(5) "three"
// ["d"]=>
// int(4)
// [0]=>
// string(1) "a"
// }
// }
Other attribute functions
Other attribute functions also include operations such as obtaining the number of data, obtaining serialized results, and directly obtaining internal array data.
var_dump($ao->count()); // int(5)
var_dump($ao->serialize()); // string(119) "x:i:2;a:5:{s:1:"a";s:3:"one";s:1:"b";s:3:"two";s:1:"c";s:5:"three";s:1:"d";i:4;i:0;s:1:"a";};m:a:1:{s:1:"a";s:3:"one";}"
var_dump($ao->getArrayCopy());
// array(5) {
// ["a"]=>
// string(3) "one"
// ["b"]=>
// string(3) "two"
// ["c"]=>
// string(5) "three"
// ["d"]=>
// int(4)
// [0]=>
// string(1) "a"
// }
In addition, the ArrayIterator object of related data can also be directly obtained through ArrayObject.
var_dump($ao->getIterator());
// object(ArrayIterator)#1 (1) {
// ["storage":"ArrayIterator":private]=>
// object(ArrayObject)#3 (2) {
// ["a"]=>
// string(3) "one"
// ["storage":"ArrayObject":private]=>
// array(5) {
// ["a"]=>
// string(3) "one"
// ["b"]=>
// string(3) "two"
// ["c"]=>
// string(5) "three"
// ["d"]=>
// int(4)
// [0]=>
// string(1) "a"
// }
// }
// }
var_dump($ao->getIteratorClass()); // string(13) "ArrayIterator"
The getIterator() method obtains an ArrayIterator object, and the getIteratorClass() method obtains the generated Iterator object type. Next we will talk about this ArrayIterator array iterator.
Array iterator
In fact, there is not much difference between the array iterator and the ArrayObject object array, and most of their methods and functions are the same. The only difference is that ArrayIterator has several more related methods in iterators. In addition, for ArrayIterator, there is no exchangeArray() method, because its essence is an iterator, not a container like ArrayObject, so If you completely switch the contents of the iterator, it is equivalent to becoming a new iterator.
$ai = new ArrayIterator(['a' => 'one', 'b' => 'two', 'c' => 'three', 'd' => 4, 0 => 'a']);
var_dump($ai);
$ai->rewind();
while($ai->valid()){
echo $ai->key(), ': ', $ai->current(), PHP_EOL;
$ai->next();
}
// a: one
// b: two
// c: three
// d: 4
// 0: a
// 游标定位
$ai->seek(1);
while($ai->valid()){
echo $ai->key(), ': ', $ai->current(), PHP_EOL;
$ai->next();
}
// b: two
// c: three
// d: 4
// 0: a
// foreach遍历
foreach($ai as $k=>$v){
echo $k, ': ', $v, PHP_EOL;
}
// a: one
// b: two
// c: three
// d: 4
// 0: a
Yes, it has more iterator-related methods than ArrayObject: valid(), next(), key(), current(), rewind(), seek().
Recursive array iterator
In addition to the normal ArrayIterator, SPL also provides iterators that can be used for deep recursive traversal. Let's take a look at the difference between it and the normal ArrayIterator.
$ai = new ArrayIterator(['a' => 'one', 'b' => 'two', 'c' => 'three', 'd' => 4, 0 => 'a', 'more'=>['e'=>'five', 'f'=>'six', 1=>7]]);
var_dump($ai);
// object(ArrayIterator)#1 (1) {
// ["storage":"ArrayIterator":private]=>
// array(6) {
// ["a"]=>
// string(3) "one"
// ["b"]=>
// string(3) "two"
// ["c"]=>
// string(5) "three"
// ["d"]=>
// int(4)
// [0]=>
// string(1) "a"
// ["more"]=>
// array(3) {
// ["e"]=>
// string(4) "five"
// ["f"]=>
// string(3) "six"
// [1]=>
// int(7)
// }
// }
// }
$rai = new RecursiveArrayIterator($ai->getArrayCopy());
var_dump($rai);
// object(RecursiveArrayIterator)#1 (1) {
// ["storage":"ArrayIterator":private]=>
// array(6) {
// ["a"]=>
// string(3) "one"
// ["b"]=>
// string(3) "two"
// ["c"]=>
// string(5) "three"
// ["d"]=>
// int(4)
// [0]=>
// string(1) "a"
// ["more"]=>
// array(3) {
// ["e"]=>
// string(4) "five"
// ["f"]=>
// string(3) "six"
// [1]=>
// int(7)
// }
// }
// }
while($rai->valid()){
echo $rai->key(), ': ', $rai->current() ;
if($rai->hasChildren()){
echo ' has child ', PHP_EOL;
foreach($rai->getChildren() as $k=>$v){
echo ' ',$k, ': ', $v, PHP_EOL;
}
}else{
echo ' No Children.', PHP_EOL;
}
$rai->next();
}
// a: one No Children.
// b: two No Children.
// c: three No Children.
// d: 4 No Children.
// 0: a No Children.
// more: Array has child
// e: five
// f: six
// 1: 7
In the data this time, our more field is a multi-dimensional array. As you can see, whether it is ArrayIterator or RecursiveArrayIterator, there is no difference in the content of the objects they print, and the difference lies in some of the methods provided by RecursiveArrayIterator.
RecursiveArrayIterator This recursive array iterator provides two methods, hasChildren() and getChildren(), which are used to determine and obtain the current traversed data value as well as subordinate child data content. Note that the content of the sub-array obtained by getChildren() here is still a RecursiveArrayIterator object.
If in an ordinary ArrayIterator, we can also complete this traversal operation through is_array(), but the data content obtained is just an ordinary array. This is the main difference between RecursiveArrayIterator and ArrayIterator.
Collection class instance
Finally, let's take a look at what the pile of things we learned today are useful for. In fact, ArrayObject, ArrayIterator, and RecursiveArrayIterator are all similar in form, and they are all traversable objects that replace array operations. But to be honest, we don’t usually use it. After all, the data structure of ordinary arrays in PHP is too powerful, and the array manipulation functions provided are also very easy to use, so what we have learned today is estimated that many students have never used it. .
After learning these contents, I immediately thought of a scene. I don't know if any old Java developers have read this article. When we wrote Java code a long time ago, we liked to add a collection to the entity bean to save the data in the form of a list of the current bean, such as the following.
// class User {
// public IList<User> userList = new ArrayList()<User>;
// public function getUserList(){
// // 查询数据库
// // .....
// for(){
// $u = new User();
// //xxxxx
// // 添加到集合中
// userList.add($u);
// }
// }
// }
In this way, after instantiating the bean externally, we can directly call the method to get the list and save the data in the userList variable. I don’t know if there is still such a way of writing, but there was indeed such a way of writing back then. If you want to correspond to PHP, we can use ArrayObject these functional classes to achieve.
class User extends ArrayObject{
public function getUserList(){
$this->append(new User());
$this->append(new User());
$this->append(new User());
}
}
$u = new User();
$u->getUserList();
var_dump($u);
// object(User)#5 (1) {
// ["storage":"ArrayObject":private]=>
// array(3) {
// [0]=>
// object(User)#4 (1) {
// ["storage":"ArrayObject":private]=>
// array(0) {
// }
// }
// [1]=>
// object(User)#6 (1) {
// ["storage":"ArrayObject":private]=>
// array(0) {
// }
// }
// [2]=>
// object(User)#7 (1) {
// ["storage":"ArrayObject":private]=>
// array(0) {
// }
// }
// }
// }
foreach($u as $v){
var_dump($v);
}
// object(User)#4 (1) {
// ["storage":"ArrayObject":private]=>
// array(0) {
// }
// }
// object(User)#6 (1) {
// ["storage":"ArrayObject":private]=>
// array(0) {
// }
// }
// object(User)#7 (1) {
// ["storage":"ArrayObject":private]=>
// array(0) {
// }
// }
Isn’t it interesting? Just inherit ArrayObject, and then you don’t even need to define the userList yourself, you can traverse the current object directly. Of course, specific business analysis, if there is such a requirement in your business needs, then you can give it a try.
Summarize
To be honest, today's content is not very commonly used content, but in some cases it can indeed bring some new ideas to our business development. The other is to clarify the difference between ArrayObject and array, as well as ArrayObject and ArrayIterator objects and data structures, so that in the right situation, we can choose the right way to achieve the functions we need.
Test code:
Reference documents:
https://www.php.net/manual/zh/class.arrayobject.php
https://www.php.net/manual/zh/class.arrayiterator.php
https://www.php.net/manual/zh/class.recursivearrayiterator.php
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。