I'm new to PHP and I'm not really familiar with classes, my question is how can I get the value of $quantity and pass it to public array which is within a class? My expected array output would be Bag => 10.
Here's my code:
$quantity = 10;
class QuantityLeft{
public array $inventory = [
'Bag' => [$quantity value here]
];
}
Option 1: provide the value through class constructor.
Option 2: Write a setter method and call it on the object
Below example implements both. The member variable should be protected against direct modification, and the setter makes validation of the input parameter to avoid illegal values.
class QuantityLeft {
protected $inventory = [];
public function __construct($quantity) {
$this->setQuantity($quantity);
}
public function setQuantity($quantity) {
if ($quantity < 0) {
throw new OutOfBoundsException('Quantity must be greater or equal 0');
}
$this->inventory['Bag'] = $quantity;
}
}
Usage:
$obj = new QuantityLeft(50);
or
$obj = new QuantityLeft(0);
$obj->setQuantity(50);
try
global $quantity =10
and than:
class QuantityLeft{
public array $inventory = [
'Bag' => global $quantity
];
}
Related
Is it possible to store value to attribute in class? If so then how?
For example:
class Student {
public $name;
public $grade;
function average() {
$sum = 0;
foreach ($this->grade as $key => $value) {
$sum += $value;
}
$avg = $sum/ count($key);
return $avg;
}
}
How to add values [math=8, history=9, biology=8] to attribute and develop method which count average of the grades?
You don't need to write any code in your class to assign values to $grade, because it's marked as public (see "Visibility" in the PHP documentation), which means code outside the class can access it.
After you create an instance of Student, you can just assign that array directly to the $grade property.
$student = new Student;
$student->grade = ['math'=> 8, 'history' => 9, 'biology'=> 8];
Instead, if you want to use that array as the default value for any new objects of this class, you can initialize the property to that value at the same time you declare it.
class Student {
public $name;
public $grade = ['math'=> 8, 'history' => 9, 'biology'=> 8];
// ...
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
public function get_entity_keyNumber($entity)
{
$this->session = Session::instance();
(int)$lastNumber = 0;
$user_data= array_keys($this->session->as_array());
$user_experience = array_filter($user_data,function($value){return strstr($value, $entity);});
if(!empty($user_experience))
{
$lastElement = end($user_experience);
(int)$lastNumber = substr($lastElement,-1);
$lastNumber++;
}
return $lastNumber;
}
this function is doing that it return me last character of last key in $user_data and Iam incrementing to it by casting it to Integer.
$user_data = array("experience0") like if i use this function:
(int)$lastNumber = get_entity_keyNumber("experience");
It will return me 1 and i will add another array to a session with name experience1 then experience2,experince3 so it cannot overwirte the keys in session
when iam using this function why is this throwing error:
Call to undefined function get_entity_keyNumber() or sometimes $entity variable undefined
Iam new to php and as well as to kohana
when using inline it works perfectly.
Try this:
$instance->get_entity_keyNumber("experience");
$instance means an instance of the class that the method get_entity_keyNumber belongs to.
In the class definition field, it'll be $this.
I'm sorry for not knowing about kohana.
I used private attribute in class with same name and assigned value of method parameter to it and used that class attribute using $this to filter array values, My OOP is weak :)
private $entity;
public function get_entity_keyNumber($entity)
{
$this->$entity =$entity;
$this->session = Session::instance();
(int)$lastNumber = 0;
$user_data= array_keys($this->session->as_array());
$user_experience = array_filter($user_data,function($value){return strstr($value, $this->entity);});
if(!empty($user_experience))
{
$lastElement = end($user_experience);
(int)$lastNumber = substr($lastElement,-1);
$lastNumber++;
}
return $lastNumber;
}
I'm having problems with an array inside a class. I can access it if I set it to static but I cannot figure out how to modify it and access it on my function if it's not static.
class Example {
protected static $_arr = array(
"count",
);
public static function run($tree) {
$_arr[] = "new";
print_r($_arr );
}
}
How do I access the array, modify it and print it from inside my public function "run"?
$_arr[] = "new";
refers to an array that will be local to your function. to access a static variable of your class, you have to use the syntax ==> self::staticVariableName
you code should be :
class Example {
protected static $_arr = array(
"count",
);
public static function run($tree) {
self::$_arr[] = "new";
print_r(self::$_arr );
}
I have just made a snippet from the code of #MQuirion . Here I wrote how to handle non-static properties in your class. I hope now you can work with your array inside your class.
class Example {
protected $_arr = array(
"count",
);
public function run($tree) {
// print new array + your properties
$this -> _arr[] = $tree;
//To print only new assigned values without your declared properties
$this -> _arr = $tree;
print_r($this->_arr );
}
}
$obj = new Example();
$tree = array('a','b','c');
$result = $obj->run($tree);
I know that in C# you can nowadays do:
var a = new MyObject
{
Property1 = 1,
Property2 = 2
};
Is there something like that in PHP too? Or should I just do it through a constructor or through multiple statements;
$a = new MyObject(1, 2);
$a = new MyObject();
$a->property1 = 1;
$a->property2 = 2;
If it is possible but everyone thinks it's a terrible idea, I would also like to know.
PS: the object is nothing more than a bunch of properties.
As of PHP7, we have Anonymous Classes which would allow you to extend a class at runtime, including setting of additional properties:
$a = new class() extends MyObject {
public $property1 = 1;
public $property2 = 2;
};
echo $a->property1; // prints 1
Before PHP7, there is no such thing. If the idea is to instantiate the object with arbitrary properties, you can do
public function __construct(array $properties)
{
foreach ($properties as $property => $value)
{
$this->$property = $value
}
}
$foo = new Foo(array('prop1' => 1, 'prop2' => 2));
Add variations as you see fit. For instance, add checks to property_exists to only allow setting of defined members. I find throwing random properties at objects a design flaw.
If you do not need a specific class instance, but you just want a random object bag, you can also do
$a = (object) [
'property1' => 1,
'property2' => 2
];
which would then give you an instance of StdClass and which you could access as
echo $a->property1; // prints 1
I suggest you use a constructor and set the variables you wish when initialising the object.
I went from c# to PHP too, so I got this working in PHP:
$this->candycane = new CandyCane(['Flavor' => 'Peppermint', 'Size' => 'Large']);
My objects have a base class that checks to see if there's one argument and if it's an array. If so it calls this:
public function LoadFromRow($row){
foreach ($row as $columnname=>$columnvalue)
$this->__set($columnname, $columnvalue);
}
It also works for loading an object from a database row. Hence the name.
Another way, which is not the proper way but for some cases okay:
class Dog
{
private $name;
private $age;
public function setAge($age) {
$this->age = $age;
return $this;
}
public function getAge() {
return $this->age;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getName() {
return $this->name;
}
}
$dogs = [
1 => (new Dog())->setAge(2)->setName('Max'),
2 => (new Dog())->setAge(7)->setName('Woofer')
];