В дополнение к использованию foreach
, как показывает Мэтт, Drink
может реализовывать интерфейсы Iterator
или IteratorAggregate
, так что вы можете перебирать напитки напрямую, скорее чем необходимость создания второго массива. Это может быть так же просто, как использовать ArrayIterator
для переноса массива данных:
<?php
class Drink implements IteratorAggregate {
function getIterator() {
return new ArrayIterator($this->dataArray);
}
#...
или вы можете написать класс для:
<?php
class DataIterator implements Iterator {
protected $data, $idx, $key, $fields;
function __construct($data, $fields = null) {
$this->data = $data;
if ($fields) {
$this->fields = $fields;
} else if (method_exists($data, 'fields')) {
$this->fields = $data->fields();
} else {
throw new InvalidArgumentException(__CLASS__ . ' expects ' . get_class($data) . " to have a 'fields' method, but it doesn't.");
}
}
/*** Iterator ***/
function current() {
return $this->data->{$this->key};
}
function key() {
return $this->key;
}
function next() {
if (++$this->idx < count($this->fields)) {
$this->key = $this->fields[$this->idx];
} else {
$this->key = null;
}
}
function rewind() {
$this->key = $this->fields[$this->idx = 0];
}
function valid() {
return ! is_null($this->key);
}
}
class Drink implements IteratorAggregate {
private $dataArray = array(
'drink_name' => null, 'drink_cals' => null,
'drink_Category' => null, 'drink_desc' => null,
'drink_price' => null
);
function __get($name) {
$method = 'get' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->$method();
}
# else return value is undefined. Could also throw an exception.
}
function __set($name, $val) {
$method = 'set' . ucfirst($name);
if (method_exists($this, $method)) {
return $this->$method($val);
}
# could throw and exception if $name isn't an accessible property.
}
/* Helps to describe Drinks by returning an array of property names.
*/
function fields() {
return array_keys($this->dataArray);
}
function getIterator() {
return new DataIterator($this);
}
# ...
}
#...
$patterns = array(
'name' => '(^[0-9a-zA-Z\s]{1,75}$)',
'calories' => '(^[0-9]{0,3}$)',
'category' => '(^[0-9A-Za-z\s]{1,50}$)',
'description' => '(^[0-9A-Za-z\s]{0,300}$)',
'price' => '(^[0-9.]{1,6}$)'
);
foreach($drinks as $i => $drink) {
foreach($drink as $propname => $propvalue) {
if(!preg_match($patterns[$propname], $propvalue)) {
return "Drink $i's $propname ('$propvalue') is invalid.";
# or:
//$errors[$i][$propname] = "'$propvalue' is invalid";
}
}
}
Свойство перегрузка (__get, __set) не требуется для итерации, но допускает доступ на запись в цикле foreach
с использованием имен свойств переменных (например, $drink->$name
). Имена свойств переменных следует использовать с осторожностью, поскольку они могут скрыть, к какому свойству обращаются, но это приемлемо в цикле foreach, поскольку ясно, что к каждому доступному свойству обращаются.
Вы можете переместить валидацию в методы set*
, создавая исключения при сбое, после чего не будет необходимости в шаге валидации.
Примечания:
не семантические . Часто его следует заменить элементами абзаца (
) и т. П., Используя стилизацию для создания пространства. Шаблоны должны быть привязаны в начале (^
) и конце ($
), в противном случае вы можете получить успешное совпадение только для части значения, что приведет к успешному выполнению проверки в случае сбоя.