php accessing an array values and keys inside a loop
Im new to php and have programmed in other languages. Im trying to solve a certain programming situation: Basically I need to access strings stored inside an object. The internal data structure of the object is an associative array. The values are the strings Im trying to access.
This is the code Im using:
<?php
class OrderAuthenticator
{
private $OrderObj;
public function __construct($Order)
{
echo 'Contructed an instance of Order Authenticator<br/>';
$this->OrderObj = $Order;
echo 'Instantiated OrderContainer<br/>';
}
public function authenticate_Drinks()
{
//echo __LINE__ ;
//4 number or characters including spaces between them
$pattern_drinkName = '([0-9a-zA-Z\s]{1,75})';
//100 characters with spaces allowed between them
$pattern_drinkCalories = '([0-9]{0,3})';
//100 characters with spaces allowed between them
$pattern_drinkCategory = '([0-9A-Za-z\s]{1,50})';
//100 characters with spaces allowed between them
$pattern_drinkDescription = '([0-9A-Za-z\s]{0,300})';
$pattern_drinkPrice = '([0-9.]{1,6})';
//echo __LINE__ ;
$DrinkContainer = $this->OrderObj->getDrinkContainer();
//echo __LINE__ ;
foreach($DrinkContainer as $Drink)
{
//print_r($Drink);
echo __LINE__ ;
echo '<br/>';
}
}
?>
This code produces the following output:
Array (
[0] => Drink Object (
[dataArray:private] => Array (
[drink_name] => SimpleXMLElement Object ( [0] => Gin )
[drink_cals] => SimpleXMLElement Object ( )
[drink_Category] => SimpleXMLElement Object ( [0] => Alocholic )
[drink_desc] => SimpleXMLElement Object ( )
[drink_price] => SimpleXMLElement Object ( [0] => 4.00 )
)
)
)
Now, what I need to do is take the string values out and I need to run a regular expression check on each of those. So I need to store each of these strings in a variable in some kind of a loop.
I had this code trying to do that within the above loop but it didnt work:
$drink_name = $Drink->getName();
echo 'drink name = '.$drink_name.'<br/>';
$drink_calories = $Drink->getCalories();
echo 'drink calories = '.$drink_calories.'<br/>';
$drink_category = $Drink->getCategory();
echo 'drink category = '.$drink_category.'<br/>';
$drink_Description = $Drink->getDescription();
echo 'drink Description = '.$drink_Description.'<br/>';
$Drink_Price = $Drink->getPrice();
echo 'drink Price = '.$Drink_Price.'<br/>';
if(!preg_match($pattern_drinkName, $drink_name))
{
echo __LINE__ ;
return 'Drink name'.$drink_name .' did not match<br/>';
}
else if(!preg_match($pattern_drinkCalories, $drink_calories))
{
echo __LINE__ ;
return 'Drink calories'.$drink_calories .' did not match<br/>';
}
else if(!preg_match($pattern_drinkCategory, $drink_category))
{
echo __LINE__ ;
return 'Drink category'.$drink_category .' did not match<br/>';
}
else if(!preg_match($pattern_drinkDescription, $drink_Description))
{
echo __LINE__ ;
return 'Drink Description'.$drink_Description .' did not match<br/>';
}
else if(!preg_match($pattern_drinkPrice, $Drink_Price))
{
echo __LINE__ ;
return 'Drink Price'.$Drink_Price .' did not match<br/>';
}
else
{
echo __LINE__ ;
return 'Merchant Location input is valid<br/>';
}
Here is the Drink class :
<?php
class Drink
{
private $dataArray;// = array();
public function __construct()
{
echo 'Entered constructor for Drink.php<br/>';
$this->dataArray = array();
}
public function setName($drink_Name)
{
echo 'Added Drink Name to DrinkObj= '.$drink_Name. '<br/>';
$this->dataArray["drink_name"] = $drink_Name;
}
public function getName()
{
echo 'Inside Drink name<br/>';
return $this->dataArray["drink_name"];
}
public function setCalories($drink_Cals)
{
echo 'Added Drink Calories to DrinkObj= '.$drink_Cals. '<br/>';
$this->dataArray["drink_cals"] = $drink_Cals;
}
public function getCalories()
{
return $this->dataArray["drink_cals"];
}
public function setCategory($drink_Category)
{
echo 'Added Drink Category to DrinkObj= '.$drink_Category. '<br/>';
$this->dataArray["drink_Category"] = $drink_Category;
}
public function getCategory()
{
return $this->dataArray["drink_Category"];
}
public function setDescription($drink_Desc)
{
echo 'Added Drink Description to DrinkObj= '.$drink_Desc. '<br/>';
$this->dataArray["drink_desc"] = $drink_Desc;
}
public function getDescription()
{
return $this->dataArray["drink_desc"];
}
public function setPrice($drink_Price)
{
echo 'Added Drink Price to DrinkObj= '.$drink_Price. '<br/>';
开发者_JAVA百科 $this->dataArray["drink_price"] = $drink_Price;
}
public function getPrice()
{
return $this->dataArray["drink_price"];
}
}
?>
$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})'
);
$DrinkContainer = $this->OrderObj->getDrinkContainer();
foreach($DrinkContainer as $Drinks)
{
foreach($Drinks as $DrinkObject)
{
$properties = array(
'name' => $DrinkObject->getName(),
'calories' => $DrinkObject->getCalories(),
'category' => $DrinkObject->getCategory(),
'description' => $DrinkObject->getDescription(),
'price' => $DrinkObject->getPrice()
);
foreach($properties as $propname => $propvalue)
{
if(!preg_match($patterns[$propname], $propvalue))
{
return "Drink $propname $propvalue did not match<br/>";
}
}
}
}
In addition to using foreach
, as Matt shows, Drink
can implement the Iterator
or IteratorAggregate
interfaces so you can iterate over drinks directly, rather than having to create a second array. It could be as simple as using ArrayIterator
to wrap the data array:
<?php
class Drink implements IteratorAggregate {
function getIterator() {
return new ArrayIterator($this->dataArray);
}
#...
or you could write a class to :
<?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";
}
}
}
Property overloading (__get, __set) isn't necessary for iteration, but does allow for write access within a foreach
loop using variable property names (e.g. $drink->$name
). Variable property names should be used sparingly as they can obfuscate what property is being accessed, but it's acceptable in a foreach loop because it's clear that every accessible property is being accessed.
You could move validation to the set*
methods, throwing exceptions on failure, at which point there would be no need for a validation step.
Notes: <br/> isn't semantic. Often, it should be replaced with paragraph (<p>) elements and the like, using styling to create space. The patterns should be anchored at the start (^
) and end ($
), otherwise you could get a successful match on just a part of a value, causing validation to succeed when it should fail.
精彩评论