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;
}
Related
I know how to call a function based off a variable like this:
$platform->ConfigurePlatform($client);
Where $platform is a variable which contains the name of the class.
I am trying to call a function like this, but object based from within the same class. The below will work fine, which is fine for within the same method.
$platform = new $platform_name();
$platform->ConfigurePlatform($client);
But I want to call another method within the object like this:
$this->$platform->GetOrdersFromPlatform();
This will give the error below:
Fatal error: Cannot access empty property (On the line above)
I thought maybe I should create the object like this instead:
$this->$platform = new $platform_name();
However this gives the error below:
Fatal error: Cannot access empty property (On the line above)
How can I achieve this?
Your question is not clear, but I think what you want is method chaining, this can be done by return the $this property of the class. Example:
class ClassName
{
function ConfigurePlatform($client)
{
// What to do
echo __METHOD__.": ".$client."\n";
// return the $this property to make the class properties chainable
return $this;
}
function GetOrdersFromPlatform($client)
{
// What to do
echo __METHOD__.": ".$client."\n";
// return the $this property to make the class properties chainable
return $this;
}
}
$classObj = new ClassName();
$client = "Firefox/Chrome/Safari";
// Call both methods
$classObj->ConfigurePlatform($client)->GetOrdersFromPlatform($client);
//ClassName::ConfigurePlatform: Firefox/Chrome/Safari ClassName::GetOrdersFromPlatform: Firrefox/Chrome/Safari
If you plan to use the same object in different places of the class, you just need to set it into an attribute of the same class.
class Station
{
public $platform = null;
public function start()
{
$this->platform = new Platform();
$this->platform->ConfigurePlatform('test');
}
public function getOrders()
{
return $this->platform->GetOrdersFromPlatform();
}
}
class Platform
{
private $orders = null;
public function ConfigurePlatform($string)
{
$this->orders = $string;
return $this;
}
public function GetOrdersFromPlatform()
{
return $this->orders;
}
}
$test = new Station();
$test->start();
echo $test->platform->GetOrdersFromPlatform();
//or
echo $test->getOrders();
This is the code tested: https://3v4l.org/UuTgb
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
Is this possible Im trying to do this with the extract() function since Im unable to get the method arguments in advance
class Test{
public function getData($id){
//use $id here
}
}
$class = 'Test'; //this is determined dymanically
$method = 'getData'; //this is also determined dynamically
$arguments = ['id'=>'1234'];
$test = new $class();
$test->{$method}(extract($arguments));
//this generates a warning Missing argument 1 for Test::getData(),
called
How can this be implemented?
EDIT
It appears I've simplified it too much, the code is intended to be the main deployment mechanism in a mini-framework Im developing so the method - getData is determined dynamically and therefore I cant know the arguments for each method in advance.
Thanks
extract is for assigning to variables. For each element of the associative array, it will assign to a variable in the current scope with that name. It returns the number of variables it assigned, not the value of any of the variables.
There's no reason to use extract in your case, just get the element of the array that you want:
$test->getData($arguments['id']);
I'm not sure why you're getting an error about a missing argument. It should pass 1 as the $id argument, since there's one element in the array.
If you don't know which elements the function needs, a better design would be to pass the whole $arguments array to the function, and let it use the parts it wants.
public function getData($args) {
$id = $args['id'];
// Use $id
}
...
$test->getData($arguments);
Just extract your array and pass $id
<?php
class Test{
public function getData($id){
echo $id;
}
}
$arguments = array('id'=>'1234');
extract($arguments);
$test = new Test();
$test->getData($id);
or
$arguments = array('id'=>'1234');
extract($arguments);
$test = new Test();
foreach($arguments as $key=>$value){
$test->getData($$key);
}
Ive found the solution using ReflectionMethod
$reflection = new \ReflectionMethod('Test', 'getData');
$pass = [];
foreach($reflection->getParameters() as $param){
//parse the method to get its arguments and filter through the sent arguments array
if(isset($args[$param->getName()])){
//check if the arguments exists and select them
$pass[] = $args[$param->getName()];
}
else{
$pass[] = $param->getDefaultValue();
}
}
//execute the resolved parameters
return $reflection->invokeArgs(new Test, $pass);
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)
The following is my simplified code
<?php
$database = new db();
$file = new file();
$input = new input();
$output = new output();
$data = "SELECT * FROM table;";
$input->page($data);
class db {
public function queryExecute($var) {
$var = $this->queryEncode($var);
$var = $this->querySubmit($var);
return $var;
}
public function queryEncode($var) {
// Do somthing
return $var;
}
public function querySubmit($var) {
// Do somthing
return $var;
}
}
The issue is when I add this to the code:
class input {
public function page($data) {
// Do something
$pageQuery = db::queryExecute($data);
}
}
With this, there are two things I have to do. First, I have to hide the errors for the db::queryExecute($data); code if the server is set to strict. And now for the second problem. I can't seem to use this line of code (which is the only way I have yet found possible for referencing other classes besides using Abstract) if the class that is being referenced is referencing yet another class but this time within it's own class.
For better explanation, the procedure is as follows:
Grab the $data variable and send it to the $input->page() function ( $input->page($data) ).
Referencing the db class, the $input->page() function sends the information onto the $database->queryExecute() function by means of the db::queryExecute() format ( db::queryExecute($data) ).
But because we are using the ::, when $database->queryExecute() references $database->queryEncode() and $database->querySubmit() using $this-> operator ( $this->queryEncode() and $this->querySubmit() ), $this-> currently belongs to $input-> and not $database->.
So what's the solution... Reference the other class differently (instead of ::)? Use a $_GLOBAL variable when I define my classes? Use something other than $this->? Configure all of the classes to use ABSTRACT/EXTENDS (or INTERFACE)?
The following error outputted refers to $var = $this->queryEncode($var);:
Fatal error: Call to undefined method input::querySubmit() in C:\[...]\global.php on line 12
Do not make static call to not static function. Pass $db instance to page, or provide global access to the database (via global registry, singleton or other method). But best, pass the dependency - the database instance, to the method.
<?php
$database = new db();
$file = new file();
$input = new input($database);
$output = new output();
$data = "SELECT * FROM table;";
$input->page($data);
class db {
public function queryExecute($var) {
$var = $this->queryEncode($var);
$var = $this->querySubmit($var);
return $var;
}
public function queryEncode($var) {
// Do somthing
return $var;
}
public function querySubmit($var) {
// Do somthing
return $var;
}
}
class input {
protected $_database;
public function __construct($database) {
$this->_database = $database;
}
public function page($data) {
// Do something
$pageQuery = $this->_database->queryExecute($data);
}
}
You can only use the double-colon operator on static, constant, or overridden properties or methods of a class. See the documentation on this. Use -> instead.