I have a class with a static method. There is an array to check that a string argument passed is a member of a set. But, with the static method, I can't reference the class property in an uninstantiated class, nor can I have an array as a class constant.
I suppose I could hard code the array in the static method, but then if I need to change it, I'd have to remember to change it in two places. I'd like to avoid this.
You can create a private static function that will create the array on demand and return it:
class YourClass {
private static $values = NULL;
private static function values() {
if (self::$values === NULL) {
self::$values = array(
'value1',
'value2',
'value3',
);
}
return self::$values;
}
}
I put arrays in another file and then include the file wherever I need it.
I am having a really really hard time understanding your question. Here is essentially what I understood:
I need to maintain a proper set, where
no two elements are the same.
PHP does not have a set type, not even in SPL! We can emulate the functionality of a set but any solution I can think of is not pleasant. Here is what I think is the cleanest:
<?php
class Set {
private $elements = array();
public function hasElement($ele) {
return array_key_exists($ele, $elements);
}
public function addElement($ele) {
$this->elements[$ele] = $ele;
}
public function removeElement($ele) {
unset($this->elements[$ele]);
}
public function getElements() {
return array_values($this->elements);
}
public function countElements() {
return count($this->elements);
}
}
Example usage:
<?php
$animals = new Set;
print_r($animals->getElments());
$animals->addElement('bear');
$animals->addElement('tiger');
print_r($animals->getElements());
$animals->addElement('chair');
$animals->removeElement('chair');
var_dump($animals->hasElement('chair'));
var_dump($animals->countElements());
Related
I'm still new to OOP and this is probably a simple question, not sure if I'm overthinking this.
Let's say we have a simple class like the following that we can use to instantiate an object that can generate an array:
class gen_arr {
public $arr = array();
public function fill_arr() {
$this->arr["key"] = "value";
}
}
// instantiate object from gen_arr
$obj = new gen_arr();
Now if you wanted to get the value of the object's array's item, would you generate an array first and then echo the value like:
$arr = $obj->fill_arr();
echo $arr["key"];
Or would you access the object's property directly?
echo $obj->arr["key"]
In the actual code the property is private and there is a method that allows the viewing of the property array, the above is just to simplify the question.
Are there performance considerations and/or just best practices when it comes to this kind of case?
UPDATE:
It's still unclear from the answers if the best way is to generate an array from the property and access that array or just access the property directly (through the getter method)
Since you are filling the array with items only on fill_arr, those items wont be availabl until you call $arr = $obj->fill_arr();.
If you want to directly call the array, then you have to fill this array on the constructor function of this call like this:
class gen_arr {
public $arr = array();
function __construct() {
$this->arr["key"] = "value";
}
}
First off, the class you shared with us has a range of problems:
its sole instance property is public and can be modified by anyone
you have some temporal coupling, the method fill_arr() needs to be invoked before accessing the the value makes any sense
Encapsulation
Reduce the visibility of the instance property from public to private, so that the property can only be modified by the object itself, and provide an accessor instead:
class gen_arr
{
private $arr;
public function fill_arr()
{
$this->arr["key"] = "value";
}
public function arr()
{
return $this->arr;
}
}
Temporal Coupling
Remove the method fill_arr() and instead initialize the property $arr in one of the following options:
initialize field lazily when accessed the first time
initialize field in the constructor
initialize field with a default value
initialize field with a value injected via constructor
Initialize field lazily when accessed the first time
Initialize the field when it's accessed the first time:
class gen_arr
{
private $arr;
public function arr()
{
if (null === $this->arr) {
$this->arr = [
'key' => 'value',
];
}
return $this->arr;
}
}
Initialize field in the constructor
Assign a value during construction:
class gen_arr
{
private $arr;
public function __construct()
{
$this->arr = [
'key' => 'value',
];
}
public function arr()
{
return $this->arr;
}
}
Initialize field with a default value
Assign a value to the field directly, which works fine if you don't need to do any computation:
class gen_arr
{
private $arr = [
'key' => 'value',
];
public function arr()
{
return $this->arr;
}
}
Initialize field with a value injected via constructor
If the values are not hard-coded or otherwise calculated (as in the previous examples), and you need to be able to instantiate objects with different values, inject values via constructor:
class gen_arr
{
private $arr;
public function __construct(array $arr)
{
$this->arr = $arr;
}
public function arr()
{
return $this->arr;
}
}
Accessing and dereferencing values
This seems like this is your actual question, so the answer is - of course - It depends!.
Let's assume we have provided an accessor instead of accessing the otherwise public field directly:
Since PHP 5.4, the following is possible:
$object = new gen_arr();
echo $object->arr()['key'];
If you are still using an older version of PHP, you obviously can't do that and have to do something like this instead:
$object = new gen_arr();
$arr = $object->arr();
echo $arr['key'];
Largely, though, the answer to this question depends on the circumstances, and what you want to achieve. After all, readability is key for maintenance, so it might just make sense for you to introduce an explaining variable.
Note About your example, you could just use an ArrayObject instead:
$arr = new \ArrayObject([
'key' => 'value',
]);
echo $arr['key']);
For reference, see:
http://wiki.c2.com/?EncapsulationDefinition
http://blog.ploeh.dk/2011/05/24/DesignSmellTemporalCoupling/
http://php.net/manual/en/language.oop5.properties.php
http://wiki.c2.com/?ItDepends
http://php.net/manual/en/migration54.new-features.php
https://refactoring.com/catalog/extractVariable.html
http://wiki.c2.com/?IntroduceExplainingVariable
http://php.net/manual/en/class.arrayobject.php
For an example, see:
https://3v4l.org/qVVBM
First fill up the array
$gen_arr = new gen_arr();
$gen_arr->fill_arr();
then get the values with a getter method
$val = $gen_arr->getValue($key);
A getter method would be like this
public function getValue($key) {
return $this->arr[$key];
}
And certailny make the $arr property private
I want to get static method from class and copy it to variable.
This is non-working example illustrating my question:
class foo
{
public static function bar($argument){ return 2*$argument; }
}
$class = new ReflectionClass('foo');
// here is no ReflectionMethod::getClosure() method in reality
$lambda = $class->getMethod('bar')->getClosure();
echo $lambda(3);
So my question: is this possible by any normal way? I find only one way for now. I can parse source file, get method source from it and convert it using create_function() but it's too perverse.
Just wrap it with closure.
$lamda = function($argument){return foo::bar($argument);};
Or you can try to use something like this
function staticMethodToClosure($class, $method) {
return function($argument)use($class, $method){return $class::$method($argument);};
}
An array in the format array($className, $methodName) is invokable as a static method call so this may work for you.
class foo
{
public static function bar($argument){ return 2*$argument; }
public static function getStaticFunction($arg){
return array("foo", $arg);
}
}
$a = foo::getStaticFunction("bar");
echo $a(5); // echos 10
So there are two things that I am stuck on now. First
class DisplayTaxonomy {
public $MyArray[]= new DisplayTaxonomy(); //the compiler says syntax error
//things I have tried
//public $ss[]= new Object();
}
Second! in a function like this:
public function whatever()
{
$Temp = new DisplayTaxonomy();
$Temp->setADTitle("1");
$MyArray[]= $Temp;//works just fine.
//then i tried to return the array
return $MyArray[];
}
I get the following
//Cannot use [] for reading in C:\xampp\htdocs\wordpress\wp-//content\themes\twentyeleven\page.php on line 52
then in the client side
$y=new DisplayTaxonomy();
$myArray[]=new DisplayTaxonomy();//works fine dont know why I cant do this in theclass.
$myArray[]=$y->getArrayOfDisplayTaxonomyObjects();
echo $myArray[0]->getADTitle();
It seems you want to create a class that handles a collection of Taxonomy objects. In that case you should have two classes, instead of making a class store instances of itself.
class TaxonomyContainer
{
private $collection = array();
public function addElement(DisplayTaxonomy $element)
{
$this->collection[] = $element;
}
public function getElements()
{
return $this->collection;
}
}
class DisplayTaxonomy
{
private $adTitle;
public function setAdTitle($adTitle)
{
$this->adTitle = $adTitle;
}
//and other functionality the Taxonomy object should have
}
Then you can avoid the ugly self replicating behaviour and separate your concerns.
$container = new TaxonomyContainer();
$element = new DisplayTaxonomy();
$container->addElement($element);
On the next level, it might be worth considering the use of one of PHP's predefined interfaces for the Container class.
You declare objects in the function body and initiate them in the constructor (or a member function). You don't use [] when returning an array, $array[] has the same functionality as array_push, nothing more.
To clarify,
class myClass {
public $obj = array();
public function __construct() {
$this->obj[] = new OtherObject();
}
public function getObj() {
return $this->obj;
}
}
You cannot do this :
class DisplayTaxonomy {
public $MyArray[]= new DisplayTaxonomy();
}
because it's like an infinite loop :) So you have to use __contruct() function.
After change the :
return $MyArray[];
to :
return $MyArray;
Your first issue is due to trying to call the class you're declaring.
class DisplayTaxonomy {
public $MyArray[]= new DisplayTaxonomy();
You should initialize your object outside of the class, in the portion of code that you need to reference the class.
In addition, the object is already an array so you can omit attaching [] to the end return $MyArray:
public function whatever(){
$Temp = new DisplayTaxonomy();
$Temp->setADTitle("1");
$MyArray[] = $Temp;
return $MyArray;
}
You're declaring the array object here:
$MyArray[]= $Temp;//works just fine
You can't call code (new DisplayTaxonomy()) when definining class properties. You'll have to assign the value in the constructor of the class:
class Foo
{
public $MyArray;
public function __construct()
{
$this->MyArray = new DisplayTaxonomy();
}
}
The other issue is that the $array[] shortcut is for appending to an array. If you want to just return the array (and not write to the array which you're asking about with []), simply skip []:
return $MyArray;
Expanded:
As Vincent Joigƞie pointed out below; you're trying to create a class with the same name as the class you're already creating. This doesn't make any sense, except for static properties. In that case you can't use __construct(), but would rather create / set the object in the static method you're calling to retrieve the object the first time:
static public function getInstance()
{
if (self::$MyArray === null)
{
self::$MyArray = new DisplayTaxonomy();
}
return self::$MyArray;
}
This is however probably not what you want, and it seems you've confused something in your logic in your class definition. Guessing freely you might just want:
class Foo
{
public $MyArray = array();
}
As array() is a static assignment (and not a function call), it's allowed in the class definition.
I can't quite understand why the output of this code is '1'.
My guess is that php is not behaving like most other OO languages that I'm used to, in that the arrays that php uses must not be objects. Changing the array that is returned by the class does not change the array within the class. How would I get the class to return an array which I can edit (and has the same address as the one within the class)?
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function getArr()
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = $t->getArr();
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
EDIT: I expected the output to be 0
You have to return the array by reference. That way, php returns a reference to the array, in stead of a copy.
<?php
class Test
{
public $arr;
public function __construct()
{
$this->arr = array();
}
public function addToArr($i)
{
$this->arr[] = $i;
}
public function & getArr() //Returning by reference here
{
return $this->arr;
}
}
$t = new Test();
$data = 5;
$t->addToArr($data);
$tobj_arr = &$t->getArr(); //Reference binding here
unset($tobj_arr[0]);
$tobj_arr_fresh = $t->getArr();
echo count($tobj_arr_fresh);
?>
This returns 0.
From the returning references subpage:
Unlike parameter passing, here you have to use & in both places - to
indicate that you want to return by reference, not a copy, and to
indicate that reference binding, rather than usual assignment, should
be done
Note that although this gets the job done, question is if it is a good practice. By changing class members outside of the class itself, it can become very difficult to track the application.
Because array are passed by "copy on write" by default, getArr() should return by reference:
public function &getArr()
{
return $this->arr;
}
[snip]
$tobj_arr = &$t->getArr();
For arrays that are object, use ArrayObject. Extending ArrayObject is probably better in your case.
When you unset($tobj_arr[0]); you are passing the return value of the function call, and not the actual property of the object.
When you call the function again, you get a fresh copy of the object's property which has yet to be modified since you added 5 to it.
Since the property itself is public, try changing:
unset($tobj_arr[0]);
To: unset($t->arr[0]);
And see if that gives you the result you are looking for.
You are getting "1" because you are asking PHP how many elements are in the array by using count. Remove count and use print_r($tobj_arr_fresh)
I'm trying to get data from a class in php5, where the data in the class is private and the calling function is requesting a piece of data from the class. I want to be able to gain that specific piece of data from the private variables without using a case statement.
I want to do something to the effect of:
public function get_data($field)
{
return $this->(variable with name passed in $field, i.e. name);
}
You could just use
class Muffin
{
private $_colour = 'red';
public function get_data($field)
{
return $this->$field;
}
}
Then you could do:
$a = new Muffin();
var_dump($a->get_data('_colour'));
<?php
public function get_data($field)
{
return $this->{$field};
}
?>
You may want to look at the magical __get() function too, e.g.:
<?php
class Foo
{
private $prop = 'bar';
public function __get($key)
{
return $this->{$key};
}
}
$foo = new Foo();
echo $foo->prop;
?>
I would be careful with this kind of code, as it may allow too much of the class's internal data to be exposed.