I'm looking at the PHP Manual, and I'm not seeing a section on data structures that most languages have, such as lists and sets. Am I just blind or does PHP not have anything like this built in?
The only native data structure in PHP is array. Fortunately, arrays are quite flexible and can be used as hash tables as well.
http://www.php.net/array
However, there is SPL which is sort of a clone of C++ STL.
http://www.php.net/manual/en/book.spl.php
PHP offers data structures through the Standard PHP Library (SPL) basic extension, which is available and compiled by default in PHP 5.0.0.
The data structures offered are available with PHP 5 >= 5.3.0, and includes:
Doubly Linked Lists
A Doubly Linked List (DLL) is a list of nodes linked in both directions to each others. Iterator’s operations, access to both ends, addition or removal of nodes have a cost of O(1) when the underlying structure is a DLL. It hence provides a decent implementation for stacks and queues.
SplDoublyLinkedList class
SplStack class
SplQueue class
Heaps
Heaps are tree-like structures that follow the heap-property: each node is greater than or equal to its children, when compared using the implemented compare method which is global to the heap.
SplHeap class
SplMaxHeap class
SplMinHeap class
SplPriorityQueue class
Arrays
Arrays are structures that store the data in a continuous way, accessible via indexes. Don’t confuse them with PHP arrays: PHP arrays are in fact implemented as ordered hashtables.
SplFixedArray class
Map
A map is a datastructure holding key-value pairs. PHP arrays can be seen as maps from integers/strings to values. SPL provides a map from objects to data. This map can also be used as an object set.
SplObjectStorage class
Source: http://php.net/manual/en/spl.datastructures.php
PHP 7 introduced an extension called ds providing specialized data structures as an alternative to the array.
The ds,
uses the Ds\ namespace.
has 3 interfaces namely,Collection, Sequence and Hashable
has 8 classes namely, Vector, Deque,Queue, PriorityQueue, Map, Set, Stack, and Pair
For more information checkout the Manual and also This blog post has some awesome information including benchmarks.
The associative array can be used for most basic data structures hashtable, queue, stack. But if you want something like a tree or heap I don't think they exist by default but I'm sure there are free libraries anywhere.
To have an array emulate a stack use array_push() to add and array_pop() to take off
To have an array emulate a queue use array_push() to enqueue and array_shift() to dequeue
An associative array is a hash by default. In PHP they are allowed to have strings as indexes so this works as expected:
$array['key'] = 'value';
Finally, you can kind of emulate a binary tree with an array with the potential to have wasted space. Its useful if you know you're going to have a small tree. Using a linear array, you say for any index (i) you put its left child at index (2i+1) and right child at index (2i+2).
All of these methods are covered nicely in this article on how to make JavaScript arrays emulate higher level data structures.
PHP has arrays, which are actually associative arrays and can also be used as sets. Like many interpreted languages, PHP offers all this under one hood instead of providing different explicit data types.
E.g.
$lst = array(1, 2, 3);
$hsh = array(1 => "This", 2 => "is a", 3 => "test");
Also, take a look in the manual.
PHP's array doubles as both a list and a dictionary.
$myArray = array("Apples", "Oranges", "Pears");
$myScalar = $myArray[0] // == "Apples"
Or to use it as an associative array:
$myArray = array("a"=>"Apples", "b"=>"Oranges", "c"=>"Pears");
$myScalar = $myArray["a"] // == "Apples"
I think you might want to be a bit more specific, when you say data structures my mind goes in a few directions...
Arrays - They are certainly well documented and available in. (http://us.php.net/manual/en/book.array.php)
SQL Data - Depends on the database you are using, but most are available. (http://us.php.net/manual/en/book.mysql.php)
OOP - Depending on the version objects can be designed and implemented. (http://us.php.net/manual/en/language.oop.php) I had to search for OOP to find this on the php site.
Of course PHP has data structures. The array in php is incredibly flexible. Some examples:
$foo = array(
'bar' => array(1,'two',3),
'baz' => explode(" ", "Some nice words")
);
Then you have an absolute plethora of array functions available to map/filter/walk/etc the structures, or convert, flip, reverse, etc.
You can always create your own if you don't feel PHP includes a specific type of data structure. For example, here is a simple Set data structure backed by an Array.
class ArraySet
{
/** Elements in this set */
private $elements;
/** the number of elements in this set */
private $size = 0;
/**
* Constructs this set.
*/
public function ArraySet() {
$this->elements = array();
}
/**
* Adds the specified element to this set if
* it is not already present.
*
* #param any $element
*
* #returns true if the specified element was
* added to this set.
*/
public function add($element) {
if (! in_array($element, $this->elements)) {
$this->elements[] = $element;
$this->size++;
return true;
}
return false;
}
/**
* Adds all of the elements in the specified
* collection to this set if they're not already present.
*
* #param array $collection
*
* #returns true if any of the elements in the
* specified collection where added to this set.
*/
public function addAll($collection) {
$changed = false;
foreach ($collection as $element) {
if ($this->add($element)) {
$changed = true;
}
}
return $changed;
}
/**
* Removes all the elements from this set.
*/
public function clear() {
$this->elements = array();
$this->size = 0;
}
/**
* Checks if this set contains the specified element.
*
* #param any $element
*
* #returns true if this set contains the specified
* element.
*/
public function contains($element) {
return in_array($element, $this->elements);
}
/**
* Checks if this set contains all the specified
* element.
*
* #param array $collection
*
* #returns true if this set contains all the specified
* element.
*/
public function containsAll($collection) {
foreach ($collection as $element) {
if (! in_array($element, $this->elements)) {
return false;
}
}
return true;
}
/**
* Checks if this set contains elements.
*
* #returns true if this set contains no elements.
*/
public function isEmpty() {
return count($this->elements) <= 0;
}
/**
* Get's an iterator over the elements in this set.
*
* #returns an iterator over the elements in this set.
*/
public function iterator() {
return new SimpleIterator($this->elements);
}
/**
* Removes the specified element from this set.
*
* #param any $element
*
* #returns true if the specified element is removed.
*/
public function remove($element) {
if (! in_array($element, $this->elements)) return false;
foreach ($this->elements as $k => $v) {
if ($element == $v) {
unset($this->elements[$k]);
$this->size--;
return true;
}
}
}
/**
* Removes all the specified elements from this set.
*
* #param array $collection
*
* #returns true if all the specified elemensts
* are removed from this set.
*/
public function removeAll($collection) {
$changed = false;
foreach ($collection as $element) {
if ($this->remove($element)) {
$changed = true;
}
}
return $changed;
}
/**
* Retains the elements in this set that are
* in the specified collection. If the specified
* collection is also a set, this method effectively
* modifies this set into the intersection of
* this set and the specified collection.
*
* #param array $collection
*
* #returns true if this set changed as a result
* of the specified collection.
*/
public function retainAll($collection) {
$changed = false;
foreach ($this->elements as $k => $v) {
if (! in_array($v, $collection)) {
unset($this->elements[$k]);
$this->size--;
$changed = true;
}
}
return $changed;
}
/**
* Returns the number of elements in this set.
*
* #returns the number of elements in this set.
*/
public function size() {
return $this->size;
}
/**
* Returns an array that contains all the
* elements in this set.
*
* #returns an array that contains all the
* elements in this set.
*/
public function toArray() {
$elements = $this->elements;
return $elements;
}
}
PHP can also have an array of arrays which is called a "multidimensional array" or "matrix". You can have 2-dimensional arrays, 3-dimensional arrays, etc.
Related
I have this array
$arr = ['field_event_start_date', 'widget', 0, 'value', '#date_part_order', 3]
And I want to convert this into this array in below format
$form['field_event_start_date']['widget'][0]['value']['#date_part_order'][3]
Trying to append the array to $form array.
I have a $form array, which contains many fields, and I want to unset a set of fields. The array above, is part of a bigger array. If I take this array, How do I convert this into array like below
$form['field_event_start_date']['widget'][0]['value']['#date_part_order'][3]
I have tried, implode like this $form[implode('][', $arr)] But this always says, undefined index.
Final code I need to run is
unset($form['field_event_start_date']['widget'][0]['value']['#date_part_order'][3]);
However, there are many like this, which number of depth varying. I need to write a generic function to achieve this.
In Drupal 8, you can use NestedArray::unsetValue() to unset a value is nested arrays. You can also use NestedArray::getValue() and NestedArray::setValue() to get and set value from nested arrays using a array of keys ($parents).
Drupal 7 only have drupal_array_get_nested_value() and drupal_array_set_nested_value(). But no drupal_array_unset_nested_value(). It can easily be ported from Drupal 8:
/**
* Unsets a value in a nested array with variable depth.
*
* This helper function should be used when the depth of the array element you
* are changing may vary (that is, the number of parent keys is variable). It
* is primarily used for form structures and renderable arrays.
*
* #param array $array
* A reference to the array to modify.
* #param array $parents
* An array of parent keys, starting with the outermost key and including
* the key to be unset.
* #param bool $key_existed
* (optional) If given, an already defined variable that is altered by
* reference.
*
* Port of NestedArray::unsetValue() from Drupal 8
*
* #see drupal_array_get_nested_value()
* #see drupal_array_set_nested_value()
*/
function drupal_array_unset_nested_value(array &$array, array $parents, &$key_existed = NULL) {
$unset_key = array_pop($parents);
$ref = &drupal_array_get_nested_value($array, $parents, $key_existed);
if ($key_existed && is_array($ref) && array_key_exists($unset_key, $ref)) {
$key_existed = TRUE;
unset($ref[$unset_key]);
}
else {
$key_existed = FALSE;
}
}
How about this:
eval("\$form['".implode("']['", $arr)."']='';");
How i can create a PHPDoc block for an declarative array?.
For example, let's say that i have the next function:
/**
* #return ??????????
*/
function dummy() {
$x1=array("key1"=>"hello","ke2"=>"world");
return $x1;
}
// ... later
$x1=dummy();
echo $x1["key1"];
I want to be explicit in the array result, instead of use #return array.
(i also tried) I also know that i can return an array of object with #return Class[] but in this case, im not using classes.
Thanks.
I am learning about Marcus Boerger's Standard PHP Library (SPL).
I have implemented my own RecursiveIterator which, by inheritence, implements the Iterator interface. It also implements Countable.
I am confused by the current(), getChildren() and hasChildren methods. That are documented at: http://www.php.net/~helly/php/ext/spl/interfaceRecursiveIterator.html
If
current() quote: 'Returns the current element', and
getChildren() returns, and I quote, 'the sub iterator for the current element'
If, as is the case for current(), the current element is taken to mean the child of the current object.
Then, surely the documentation is specifying that getChildren(), in effect, returns the grandchildren of the node in question.
Hence confused.
<?php
/**
*#desc Represents a node within a hierarchy
*/
class RecursableCountableIterableNode implements RecursiveIterator, Countable
{
public $title;
private $_componentsArray;
private $_iteratorPosition;
/**
*#desc adds component
*/
public function addComponent(
RecursableCountableIterableNode $incomingNodeObj
)
{
foreach ( $this->_componentsArray as $componentNodeObj )
{
if ( $incomingNodeObj === $componentNodeObj )
{
//its is already in there
return;
}
}
//add to the next element of the numerically indexed array
$this->_componentsArray[] = $incomingNodeObj;
}
/**
* #desc RecursiveIterator Interface
*/
/**
* #desc Implements the RecursiveIterator Interface
* #return boolean - Whether or not the node at the current element
* has children.
*
* Note: This method does NOT count the children of this node,
* it counts the components of the node at the *current* element.
* There is a subtle but important difference.
* It could have been better to name
* the interface method 'hasGrandChildren()'.
*/
public function hasChildren()
{
return ( boolean ) count( $this->current() );
}
/**
* #desc Gets the node of the current element which in effect is a container
* for childnodes.
*
* Note: According to the SPL, it does NOT get 'the child elements of
* the current node' ($this->_componentsArray) which was a surprise to me.
*
* #return RecursableCountableIterableNode - the
* sub iterator for the current element
*
*/
public function getChildren()
{
return $this->current();
}
/**
* #desc To adhere to countable interface.
* #returns integer - The number of elements in the compondents array.
*/
public function count()
{
return count( $this->_componentsArray );
}
/**
* Iterator methods
*/
/**
* #desc Rewind the iterator to the first element.
* #return void
*/
public function rewind()
{
$this->_iteratorPosition = 0;
}
/**
* #desc Return the current element.
* #return RecursableCountableIterableNode
*/
public function current()
{
return $this->_componentsArray[ $this->_iteratorPosition ];
}
/**
* #desc Return the key of the current element.
* #return integer
*/
public function key()
{
return $this->_iteratorPosition;
}
/**
* #desc Move forward to the next element.
* #return void
*/
public function next()
{
++$this->_iteratorPosition;
}
/**
* #desc Checks if current position has an element
* #return boolean
*/
public function valid()
{
return isset( $this->_componentsArray[ $this->_iteratorPosition ] );
}
}
In the class above, getChildren() returns an object that implements RecursiveIterator and Countable. Because each RecursableCountableIterableNode object holds instances of other RecursableCountableIterableNode objects. I think its a form of Composite pattern.
Through experimentation I have managed to perform a recursive operation on the tree by using count() (as a terminal condition to exit the recursive process) and foreach to iterate over each node's children.
What's interesting is that, in effect, the count feature implicity does a hasChildren operation and the foreach construct is implicitly doing a getChildren operation in order to perform recursive traversal.
class NodeTreeProcessor
{
protected $output = '';
public function doProcessingWithNode(
RecursableCountableIterableNode $treeNodeObj
)
{
$this->output .= $treeNodeObj->title;
//Base case that stops the recursion.
if (!( count( $treeNodeObj ) > 0 ))
{
//it has no children
return;
}
//Recursive case.
foreach( $treeNodeObj as $childNode )
{
$this->doProcessingWithNode( $childNode );
}
}
}
Given that, I am thinking that in order to be a practical RecursiveIterator,
getChildren really ought to return $this instead of the node at current(), and
hasChildren really ought to return the boolean cast result of count($this)
is this right?
The specs say one thing - which I take literally. But my practical experience says another.
I don't think its right to say "grand children". You're just changing your reference point from the an element of current iterator, to the current iterator, which makes the children into grand children. I don't see a good reason to do that, because it's just not the convention I'm accustomed to with spl iterators.
I recomend you stick to code like what you posted, but I think maybe you're unaware of RecursiveIteratorIterator. A RecursiveIteratorIterator is meant to be a thing that will handle the complexity of calling hasChildren() and getChildren(), and maintain a proper stack of iterators in the process. In then end, you're presented with what appears to be a flattened list of your hierarchy. Your NodeTreeProcessor class is currently doing some of this stuff. Then you can just foreach over the RecursiveIteratorIterator, and you'll get a breadth first or depth first iteration depending on what flags you used. You don't have to use RecursiveIteratorIterator though.
Also, consider returning a new outer iterator when getChildren() is called. Otherwise, you forgo the possibility of iterating over the same node with more than one iterator at a time, because the position of your iterator will be shared state. Currently, you're using the inner iterator paradigm, where both the data, and the state of iteration is stored in the same object. An outer iterator detaches the the iteration state from the data, letting you have more than 1 active iterator over the same piece of data.
So i have a string, representing several objects (tags in this case)
i.e.: "php,mysql,doctrine2"
Let's say my database already has "php" and "doctrine2".
Now i want the best way to add the missing elemets (in this case mysql).
Should i create an object for every element and just use persist/sync or something, or is there a better way?
I need all the objects at the end anyway to add them to a new object (with a simple many-to-many relation) anyway.
I'd be happy about any suggestions.
1) Pull out all your tag names with a single query into an array
2) Use array_filter along with a closure to detect tags not present in the dataset
3) Create an insert for the new tags
$currentTags = getCurrentTagsArray();
$newTags = explode(',', 'php,mysql,doctrine2');
$newTagsToSave = array_filter($currentTags, function($item) use ($newTags){
if (in_array($item, $newTags))
{
return false;
}
return true;
});
Or...
You can use Doctrine 2's ArrayCollection wrapper (\Doctrine\Common\Collections\ArrayCollection()) it has pretty much the same implementation above as a filter method (you still need to pass the closure).
$myCollection->filter($closure);
I had a similar problem where I had to synchronize an entity collection with an external source. However, my problem required not only additions, but also updates and deletes. I used code to diff the ArrayCollection with another array, and call CRUD methods add based on the differences. As far as I can tell from the docs, doctrine doesn't natively handle this. Average performance should be O(n) but takes some memory.
/**
* #param array $source - the array we are starting with
* #param array $new - the array we want to end with
* #param $fnHash - function used to determine object equality, not based on object id
* #param $fnUpdate - function to perform update of existing object, takes current object and new object as params
* #param $fnAdd - function to perform insert
* #param $fnDelete - function to perform delete
*/
public static function syncArrays(array $source, array $new,
$fnHash, $fnUpdate, $fnAdd, $fnDelete)
{
// make modifiable array copies mapped by hashes of the elements
$sourceKeys = array_map($fnHash, $source);
$hasKeys =count($sourceKeys) > 0;
$newarray = ($hasKeys) ? array_combine(array_map($fnHash, $new), $new) : $new;
if ($hasKeys) { // true => may have updates or deletes
$sourcearray = array_combine($sourceKeys, $source);
// updates
foreach ($sourceKeys as $hashkey) {
if (isset($sourcearray[$hashkey]) && isset($newarray[$hashkey])) {
$fnUpdate($sourcearray[$hashkey], $newarray[$hashkey]);
unset($sourcearray[$hashkey]);
unset($newarray[$hashkey]);
}
}
// deletes
foreach ($sourcearray as $entity) {
$fnDelete($entity);
}
}
//adds
foreach ($newarray as $entity) {
$fnAdd($entity);
}
}
The way I call it to update my doctrine association $parentEntity->getPayments() is:
ArrayHelper::syncArrays($parentEntity->getPayments()->toArray(), $newPayments,
function($entity) {return $a->getName();}, // hash function
function($current, $new) {
$current->setTotal($new->getTotal()); // update function
},
function($a) use ($parent, $manager) {
$parent->addVendorPaymentObject($a); // add function
$manager->persist($a);
},
function($a) use ($manager) { // delete function
$manager->remove($a);
}
);
Is there a syntax for documenting functions which take a single configuration array, rather than individual parameters?
I'm thinking specifically of CodeIgniter-style libraries, which use a mechanism similar to this:
<?php
//
// Library definition
//
class MyLibrary {
var $foo;
var $bar;
var $baz;
// ... and many more vars...
/* Following is how CodeIgniter documents their built-in libraries,
* which is mostly useless. AFAIK they should be specifying a name
* and description for their #param (which they don't) and omitting
* #return for constructors
*/
/**
* #access public
* #param array
* #return void
*/
function MyLibrary($config = array()) {
foreach ($config as $key => $value) {
$this->$key = $value;
}
}
}
//
// Library usage:
//
// Iniitialize our configuration parameters
$config['foo'] = 'test';
$config['bar'] = 4;
$config['baz'] = array('x', 'y', 'z');
$x = new MyLibrary($config);
?>
So my question is, is there some supprted way of documenting the configuration array beyond just the purely textual description? Actually specifying a proper #param [type] [name] [desc] that allows PHPDoc to parse out useful values?
As an aside, CodeIgniter really does just overwrite it's own values with those passed in via the $config array as above, effectively allowing you to clobber private members. I'm not a fan, but I'm stuck with it.
I've never seen any "good" way of documenting this -- and I've never seen anything that could be used by IDEs (such as Eclipse PDT) for parameters hinting either :-(
I would have said "do like your framework does", but as you said, what it does, here, is not quite good enough...
Maybe a quick/sort list of possible keys might be better than nothing, though ; a bit like this :
#param array $config [key1=>int, otherKey=>string]
Not sure how it would be interpreted by phpDocumentor or an IDE... But might be worth a try ?
This is, btw, one reason why I tend to avoid that kind of way of passing parameters -- at least when there are not too many (optional) parameters to a method.
The correct array #param notation for arrays is as specified in PHPlint
You can use it to document a config array in a useful manner:
Example:
/**
* Does stuff
*
* #param array[int|string]array[string]Object $config
*
* #return array[int]string
*/
public function foo(array $config)
{
// do stuff here
return array('foo', 'bar', 'baz');
}
You can do this:
/**
* #param array $param1
* #param string $param1['hello']
*/
function hey($param1)
{
}
and netbeans will pick it up but phpdoc messes up the documentation
I always use <pre> tags in situations like this. Ex.:
/**
* #param array $ops An array of options with the following keys:<pre>
* foo: (string) Some description...
* bar: (array) An array of bar data, with the following keys:
* boo: (string) ...
* far: (int) ...
* baz: (bool) ...
* </pre>
*/
Most IDEs and documentation generators I have used seem to render this in a reasonable way, though of course they don't provide any type checking or inspection of the array parameters.
There is currently no "official" (as in 'supported by multiple tools') way to do this.
The PHP FIG is discussing it at the moment at https://groups.google.com/d/topic/php-fig/o4ko1XsGtAw/discussion
A text description, to whatever degree of completeness you want, is really your only option. You can make it as legible as you want, but code analysis tools (phpDocumentor, IDE support) have no way to know how your $array is actually structured at runtime.
I agree with the many commenters that writing code this way exchanges coding convenience for code legibility.
I've used classes.
<?php
class MyLibrary {
var $foo;
var $bar;
var $baz;
/**
* #param MyLibraryConfig|null $config
*/
function MyLibrary( $config = null ) {
if ( isset( $config->foo ) ) {
$this->foo = $config->foo;
}
if ( isset( $config->baz ) ) {
$this->baz = $config->baz;
}
if ( isset( $config->bar ) ) {
$this->bar = $config->bar;
}
}
}
/**
* #property string $foo
* #property int $bar
* #property array $baz
*/
class MyLibraryConfig {
}
It works fairly well, main problem is that the code becomes littered with specific classes. They can be nested so parts of configuration can be reused.