Dynamic method name - php

First of all sorry for the title, but i had no clue how i should name it.
Let's say i have it like that:
$lang = new lang;
$lang->setLanguage('en');
$string = $lang->get('Willkommen');
This would output Welcome for example.
But what i want is this:
$lang = new lang;
$lang->setLanguage->en
$string = $lang->get->Willkommen
As you thought, this should also output Welcome.
In order words, i want the same result, but without having to pass arguments to the instance.
I searched a long time now, but could not find out how i could do that.

Sounds like you're looking for the __get magic method.
class lang {
var $language = 'en';
function __get($prop) {
if ($prop == 'Willkommen') {
if ($this->language == 'en') return 'Welcome';
else if ($this->language == 'fr') return 'Bonjour';
}
}
function __set($prop, $val) {
if ($prop == 'language') $this->language = $val;
}
}
$lang = new lang();
echo $lang->Willkommen; // Prints "Welcome"
$lang->language = 'fr';
echo $lang->Willkommen; // Prints "Bonjour"

In php, dynamic access is with {} :
$key = 'Willkommen';
$lang->{$key};

Related

Arrays in php oop

I have array, where i put data depend on the url. But there is the problem, i can not print this array like in the simple php:
$array = ["hi", "name"]; echo $array[1];
what is wrong in my code that i will show, and how i can print the array
Code:
<?php
class Translate {
public $transl = [];
public function getTransl($transl = []) {
if (( isset($_GET['lang']))) {
if ($_GET['lang'] == "en") {
$this->transl = ['word1', 'word2'];
}
if ($_GET['lang'] == "ru") {
$this->transl = ['word3', 'word4'];
}
}
}
}
$test = new Translate();
$test->getTransl([0]);
?>
No idea, why are you using $transl = [] in method parameter when you need specific index, here you can just pass key which you need.
Example:
<?
class Translate {
public $transl = 0;
public function getTransl($transl = '') {
if (( isset($_GET['lang']))) {
if ($_GET['lang'] == "en") {
$this->transl = ['word1', 'word2'];
}
if ($_GET['lang'] == "ru") {
$this->transl = ['word3', 'word4'];
}
}
return $this->transl[$transl];
}
}
$test = new Translate();
echo $test->getTransl(0); // this will print `word1` if $_GET['lang'] equal to `en`
?>
In your code, you are not using either echo or return in your method to get the result, and you are not matching $transl with $this->transl anywhere to get the specific index.
First, you don't pass the index as a parameter. You use it as an index. Proper syntax would be:
$test->getTransl()[0];
That assumes that $test->getTransl() returns an array. But it doesn't. It doesn't return anything. It just sets the class attribute $transl. So, you have to do it in two lines:
$test->getTransl(); // This sets the attribute
$test->transl[0]; // This uses the attribute
But, that goes against that the method implies. The method implies that it returns the transl attribute. So, you SHOULD return it in the function with:
return this->transl;
Then, you can use:
$test->getTransl()[0];
Of course, this won't print anything. You need to precede with with echo or print:
echo $test->getTransl()[0];
I think you'll just need to return the output.
Let's say you have a file named test.php on your server
class Translate {
public $transl = [];
public function getTransl($transl = []) {
if (( isset($_GET['lang']))) {
if ($_GET['lang'] == "en") {
$this->transl = ['word1', 'word2'];
}
if ($_GET['lang'] == "ru") {
$this->transl = ['word3', 'word4'];
}
}
return $this->transl;
}
}
$test = new Translate();
$output=$test->getTransl([0]);
echo "<pre>";
print_r($output);
echo "</pre>";
Running http://server/{{enterfolderhere}}/test.php?lang=en in your browser will give
Array
(
[0] => word1
[1] => word2
)
Running http://server/{{enterfolderhere}}/test.php?lang=ru in your browser will give
Array
(
[0] => word3
[1] => word4
)
There are a few issues with your code as others have pointed out. But from a code structure point of view, there are some more fundamental issues (IMHO).
If you are going to create a translator, basing it on if $_GET variables means it can be difficult to test. In this example, you send in a language you want in the constructor and then the class will just set the private translator variables to the table of translations.
Secondly - using numeric values for the word your after can be prone to errors (so can this method, but less so). In this case, the key of the translation is the word you want to start with and the value is the new word, so rather than
echo $test->getTransl(0);
you use
echo $russianTrans->getTransl("word2");
This is the code, hope it helps...
class Translate {
// Use private variables whenever possible
private $transl = [];
public function __construct( string $lang ) {
if ($lang == "en") {
$this->transl = ['word1' => 'word1', 'word2' => 'word2'];
}
if ($lang == "ru") {
$this->transl = ['word1' => 'word3', 'word2' => 'word4'];
}
}
public function getTransl($word) {
return $this->transl[$word];
}
}
$russianTrans = new Translate($_GET['lang']); // Or hardcode it to 'ru' for example
echo $russianTrans->getTransl("word2");

How Can we pass function parameter as another function which itself has different parameters?

I have function below :
function cache_activity_data($cid,$somefunction) {
$cache_time = '+15 minutes';
$cache_id = $cid;
$expire = strtotime($cache_time);
$cache = cache_get($cache_id);
if (!empty($cache->data)) {
if (time() > $cache->expire) {
cache_clear_all($cache_id, 'cache_custom_activity_dashboard');
$report = $somefunction; // will get from function
cache_set($cache_id, $report, 'cache_custom_activity_dashboard', $expire);
}
else {
$report = $cache->data;
}
}
else {
$report = $somefunction; // will get from function
cache_set($cache_id, $report, 'cache_custom_activity_dashboard', $expire);
}
return $report;
}
Now $somefunction can be like below examples :
total_comments_per_user($user->uid);
total_comments_per_user_time_limit($user->uid, $user_year_start);
total_revisions_time_limit($month_ago);
total_revisions_time_limit($year_start);
every time I need to pass like 20 different functions. Is that possible I am getting error as at place of varibales I am passing function But I am not able to figure is that possible.
How I want to use :
//want to write this as function
$cache_revisions_total = cache_get("total_revisions", "cache_custom_activity_dashboard");
if (!empty($cache_revisions_total->data)) {
if (time() > $cache_revisions_total->expire) {
cache_clear_all("total_revisions", 'cache_custom_activity_dashboard');
$t_revisions = total_revisions();
cache_set("total_revisions", $t_revisions, 'cache_custom_activity_dashboard', $expire);
}
else {
$t_revisions = $cache_revisions_total->data;
}
}
else {
$t_revisions = total_revisions();
cache_set("total_revisions", $t_revisions, 'cache_custom_activity_dashboard', $expire);
}
// want to write this as function end here
$vars['total_bubbla_rev'] = number_format(($t_revisions / $days_from_rev_start), 2, '.', '');
// here i want to do same so i need to write function or should i repeat code
$y_revisions = total_revisions_time_limit($year_start);
$vars['yearly_bubbla_rev'] = number_format(($y_revisions / $year_days), 2, '.', '');
// here i want to do same so i need to write function or should i repeat code
$m_revisions = total_revisions_time_limit($month_ago);
$vars['monthly_bubbla_rev'] = number_format(($m_revisions / 30), 2, '.', '');
Please suggest, Thanks!
I see two possible options.
Option 1
You could use Anonymous functions. I simplified your function but you'll get the idea:
function cache_activity_data($cid, $somefunction) {
$report = $somefunction();
}
Define your functions as anonymous functions:
$parm1 = "banana";
$parm2 = "fruit";
$your_function1 = function() use ($parm1, $parm2) {
echo "$parm1 is a $parm2";
};
$your_function2 = function() use ($parm1) {
echo $parm1;
};
Usage:
cache_activity_data($cid, $your_function1); // shows "banana is a fruit"
cache_activity_data($cid, $your_function2); // shows "banana"
Read carefully through the documentation. Especially the part about variable scopes.
Option 2
Another possibility is call_user_func_array() but this requires you to make a little adjustment to cache_activity_data(). You need to add a third parameter which holds an array:
function cache_activity_data($cid, $somefunction, $somefunction_parms) {
$report = call_user_func_array($somefunction, $somefunction_parms);
}
Define your functions as usual:
function your_function1($parm1, $parm2) {
echo "$parm1 is a $parm2";
}
function your_function2($parm) {
echo $parm;
}
Usage
cache_activity_data($cid, "your_function1", array("banana", "fruit")); // shows "banana is a fruit"
cache_activity_data($cid, "your_function2", array("banana")); // shows "banana"
First, you cannot pass functions as parameters, however you can use callbacks as explained here:
http://php.net/manual/en/language.types.callable.php
But in your case, this seems irrelevant as you are not determining the function or changing its value in cache_activity_data().
Therefore, you might want to do like this:
$reportDefault = total_comments_per_user($user->uid);
// Or ... $reportDefault = total_revisions_time_limit, total_comments_per_user_time_limit, etc..
$report = cache_activity_data($cid, $reportDefault);
You do not need to add pass $report or any function as parameter.

PHP: how to resolve a dynamic property of an object that is multiple levels deep

I am have written a helper function to "cleanup" callback variables for input into MySQL. This is the function that I wrote:
public function string($object, $objectPath) {
if (!empty($object->$objectPath) || $object->$objectPath !== '') {
$value = $object->$objectPath;
} else {
return 'NULL';
}
if (!empty($value) || $value != '') {
return "'".str_replace("'","''",$value)."'";
} else {
return 'NULL';
}
}
Now, $object is always an object returned by the call, and $objectPath is always a string to points to a given value. Here's where the problem comes in. This works:
$value = $this->db->string($object, 'foo');
However, this does not work:
$value = $this->db->string($object, 'foo->bar->foo1->bar1');
Whenever $objectPath is more than "one layer" deep, I get the following error from (Amazon's) client library:
Fatal error: Call to undefined method MarketplaceWebServiceOrders_Model_Order::getFoo->Bar() in /path/to/Model.php on line 63
The code block that the error refers to is this:
public function __get($propertyName)
{
$getter = "get$propertyName";
return $this->$getter(); // this is line 63
}
$object is not XML, so I can't use SimpleXMLElement and XPath.
What is the problem with my code? Is it that am I concatenating an object and a string? If so, how can I make that possible? How can I get this function to do what I intended it to do?
By the way, I'm using PHP 5.4.27.
PHP doesn't automatically resolve a string containing multiple path levels to children of an object like you are attempting to do.
This will not work even if $obj contains the child hierarchy you are expecting:
$obj = ...;
$path = 'level1->level2->level3';
echo $obj->$path; // WRONG!
You would need to split up the path and "walk" through the object trying to resolve the final property.
Here is an example based on yours:
<?php
$obj = new stdClass();
$obj->name = 'Fred';
$obj->job = new stdClass();
$obj->job->position = 'Janitor';
$obj->job->years = 4;
print_r($obj);
echo 'Years in current job: '.string($obj, 'job->years').PHP_EOL;
function string($obj, $path_str)
{
$val = null;
$path = preg_split('/->/', $path_str);
$node = $obj;
while (($prop = array_shift($path)) !== null) {
if (!is_object($obj) || !property_exists($node, $prop)) {
$val = null;
break;
}
$val = $node->$prop;
// TODO: Insert any logic here for cleaning up $val
$node = $node->$prop;
}
return $val;
}
Here it is working: http://3v4l.org/9L4gc
With #itsmejodie's help, I finally got a working solution:
public function string($node, $objectPath) {
$value = NULL;
$path = explode('->', $objectPath);
while (($prop = array_shift($path)) !== NULL) {
if (!$node->$prop) {
break;
}
$value = $node->$prop;
$node = $node->$prop;
}
if (is_string($value)) {
return "'".str_replace("'","''",$value)."'";
} else {
return 'NULL';
}
}
The key for me was to see that, as #itsmejodie put it, "PHP doesn't automatically resolve a string containing multiple path levels to children of an object." In a string like, 'foo->bar->foo1->bar2', PHP won't convert the ->'s into the T_OBJECT_OPERATOR, thus appending a string to an object, e.g., $object->foo->bar->foo1->bar2, just won't work.

How to access a member variable of different function in a codeigniter controller

//first function
function insertdigit(){
$userdigit=5;
$flag = $this->usermodel->userdigitmodel($userdigit);
$value = array(
'result' => $flag
);
echo json_encode($value);
if ($flag == true) {
return $userdigit;
} else {
}
}
//second function
function usedigit(){
$data['userdigit']=$this->insertdigit();
}
but i get {"result":true} goes back to the function? how to access a member variable in a different member function
Try to remove echo json_encode($value); in your code.
If you need to access a parameter in several functions on your controller, you have to create it outside your function so it will be available for all your controller functions.
So, in your case it should be something like this:
class Test extends Controller
{
private $userdigit; //here you can set a default value if necessary: private $userdigit = 5
function insertdigit(){
$this->userdigit=5;
$flag = $this->usermodel->userdigitmodel($this->userdigit);
$value = array(
'result' => $flag
);
echo json_encode($value);
if ($flag == true) {
return $this->userdigit;
} else {
}
}
//second function
function usedigit(){
$data['userdigit']=$this->userdigit;
}
}
This way your userdigit variable is available for all your functions. With $this you are telling PHP that you are trying to access something inside the class.
This link contain more and useful information: http://www.php.net/manual/en/language.oop5.properties.php
Is that what you really need?
A possible solution:
function insertdigit()
{
$userDigit = 5;
$flag = $this->usermodel->userdigitmodel($userDigit);
$value = array
(
'result' => $flag
);
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
{
echo json_encode($value);
}
if ($flag == true)
{
return $userdigit;
}
else
{
}
}
//second function
function usedigit()
{
$data['userdigit'] = $this->insertdigit();
}
The above code, in insertdigit detects if there is an Ajax request and if so, it will echo out the json_encoded data. If you call it in an normal request, i.e. via usedigit it won't echo the json_encoded data (unless you are calling usedigit via an Ajax request).
Your question doesn't really explain what you are doing, so it's hard to explain a better solution, however, if you are trying to access a "variable" in more than one place, you should really separate your code so you have a single entry point for that variable.
Is your variable dynamic, or is it static?

jquery dynamic url

I have a form and the url for submitting the form will generated dynamicly
var Var1 = new Array();
var Var2 = new Array();
if(Var1.length === 0)
$(this).attr('action', 'http://localhost/Method' ).submit();
if(Var1.length != 0 && Var2.length === 0)
$(this).attr('action', 'http://localhost/Method/Var1').submit();
if(Var1.length != 0 && Var2.length != 0)
$(this).attr('action', 'http://localhost/Method/Var1/Var2').submit();
and all that URLs fires one method in the server and it is
public function Method(){}
public function Method(Var1){}
public function Method(Var1 , Var2){}
is there anyway to make all the last 3 methods as one method? something like this:
public function Method(Var1, Var2){
if( condition for Var1 ){// doSomthing}
if( condition for Var2 ){// doSomthing}
}
If you need this function for PHP, you can use func_get_arg and func_num_args:
public function Method() {
$numArguments = func_num_args();
if ($numArguments >= 1) {
$argument1 = func_get_arg(0);
// Do something with argument 1
}
if ($numArguments >= 2) {
$argument2 = func_get_arg(1);
// Do something with argument 2
}
}
If all the three url calls a single method in your server you can use the default argument mechanism.
public function Method($Var1=null, $Var2=null){
if(is_null($Var1)){// doSomthing}
if(is_null($Var2)){// doSomthing}
}
Obviously to map these urls you need to use some sorts of router logic. And the router must dispatch the proper method of the object.
For exmaple if your url is something like /index.php/Object/method/param1/param2, index.php should create the proper object first.
$parts = explode('/', $_SERVER['REQEUST_URI']);
array_shift($parts); // emtpy part
array_shift($parts); // index.php
$cls = array_shift($parts) // Object
$obj = new $cls;
And then dispatch the method.
$method = array_shift($parts);
call_user_func_array(array($obj, $method), $parts);
public function Method(){
$root = 'http://localhost/Method/',
$Var1 = func_get_args(0) || '',
$Var2 = func_get_args(1) || '';
if($Var1 && $Var2) $root .= $Var1 + '/' + $Var2;
else if($Var1 && !$Var2) $root .= '/' + $Var1;
}

Categories