KoihimeNakamura
KoihimeNakamura

Reputation: 87

I need some help accessing a member function in a protected array in PHP

Right now I'm trying to write a function that would allow me to access member functions. The code in question looks a little like this:

protected $formName;
protected $formClass;
protected $formAction;
protected $formMethod;
protected $formObjArray = array(); //outputs in order. So far it should only take newLine, selectTag, inputTag, textTag.
protected $submitBtnVal;
protected $encType;

function __construct($args) {
  $this->formName = $args['formName'];
  $this->formAction = $args['formAction'];

  if (isset($args['formClass'])) $this->formClass = $args['formClass'];
  if (isset($args['encType'])) $this->encType = $args['encType'];

  //default should be POST. Hell, you should never really be using GET for this..
  //also, the default submit value is Submit
  $this->formMethod = isset($args['formMethod']) ? $args['formMethod'] : "POST"; 
  $this->submitBtnVal = isset($args['submitBtnVal']) ? $args['submitBtnVal'] : "Submit";
}

//get functions
function getFormName () { return $this->formName; }
function getFormAction () { return $this->formAction; }
function getFormMethod () { return $this->formMethod; }
function getSubmitBtnVal () { return $this->submitBtnVal; }
function getEncType () { return $this->encType; }

//set functions
function setFormName ($newName) { $this->fromName = $newName; }
function setFormAction ($newAction) { $this->formAction = $newAction; }
function setFormMethod ($newMethod) { $this->formMethod = $newMethod; }
function setEncType ($newEType) { $this->encType = $newEType; }

function addTag($newTag) {
  if ($newTag instanceof formTag || $newTag instanceof fieldSetCont || $newTag instanceof newLine
      || $newTag instanceof noteTag)
    $this->formObjArray[] = $newTag;
  else throw new Exception ("You did not add a compatible tag.");
}

I'd like to be able to call $myForm->getTagByName("nameA")->setRequired(true);

How would I do that? Or would I need to do something more like..

$tagID = $myForm->getTagByName("nameA");
$myForm->tagArray(tagID)->setRequired(true);

Upvotes: 0

Views: 106

Answers (2)

ziad-saab
ziad-saab

Reputation: 20269

In your addTag method, you are storing new tags in $this->formObjArray using the [] notation, which will just append the new tag to the end of the array. If your tag objects all have a getName() method, then you can do something like this:

$this->formObjArray[$newTag->getName()] = $newTag;

Then, you can easily add a getTagByName() method:

public function getTagByName($name) {
  if (array_key_exists($name, $this->formObjArray) {
    return $this->formObjArray($name);
  }
  else {
    return null;
  }
}

Please beware of the solutions suggesting you to iterate through all the tags in your array! This could become very costly as your form gets larger.

If you need to use the [] construct because the order of the elements added is important, then you can still maintain a separate index by name, $this->tagIndex, that will be an associative array of name => tag. Since you are storing object references, they will not be using much space. Assuming that getTagByName will be used many times, this will save you a lot of resources over iterating the tags array on every call to getTagByName.

In that case, your addTag method would look like this:

$this->formObjArray[] = $newTag;
$this->tagIndex[$newTag->getName()] = $newTag; // it seems that you're doubling the memory needed, but you're only storing object references so this is safe

EDIT : Here is some modified code to account for the fact that multiple tags can have the same name:

In your addTag() method, do:

$this->formObjArray[] = $newTag;
$tag_name = $newTag->getName();
if (!array_key_exists($tag_name, $this->tagIndex)) {
  $this->tagIndex[$tag_name] = array();
}
$this->tagIndex[$tag_name][] = $newTag

You can then rename getTagByName to getTagsByName and get the expected result.

As mentioned in the comments, this is only useful if you will call getTagsByName multiple times. You are trading a little additional memory usage in order to get quicker lookups by name.

Upvotes: 1

Okonomiyaki3000
Okonomiyaki3000

Reputation: 3696

Nothing in your code seems to be protected so you should have no trouble accessing any of it.

It looks like all your tags are in $formObjArray so it should be trivial to filter than array and return tags that match the name you've passed in. The trouble you will have is that, getTagByName really should be getTagsByName and should return an array because you can have more than one tag with the same name. Since it will return an array, you can not call setRequired on the return value, arrays don't have such a method. You'll need to do it more like:

$tags = $myForm->getTagsByName("nameA");
foreach ($tags as $tag) {
    $tag->setRequired(true);
}

Exactly what are you stuck on? Maybe I don't understand the question very well.

So maybe the filtering has you stuck? Try this (if you you're using at least php 5.3)

function getTagsByName($tagname) 
{
    return array_filter($this->formObjArray, function($tag) use($tagname) { 
        return $tag->getName() == $tagname; 
    });
}

No ifs or switches.

Prior to 5.3, you don't have lambda functions so you need to do it differently. There are several options but this may be the simplest to understand:

function getTagsByName($tagname) 
{
    $out = array();
    foreach ($this->formObjArray as &$tag) {
        if ($tag->getName() == $tagname) {
            $out[] = $tag;
        }
    }
    return $out;
}

Upvotes: 2

Related Questions