I've got this weird bug which i'm hoping someone here can help me with, or at least explain why it is happening.
I'm using the __call method ;
public function __call($method, $params) {
var_dump($params);
echo '<br/><br/>';
}
I call this with per example:
$params = array('index' => 0, 'apikey' => 'aasdf');
$client->notAFunction($params)
This is a non-existent method, so it will go into __call with $method = notAFunction and my array in $params.
My expected output from __call would be;
array(2) { ["index"]=> int(0) ["apikey"]=> string(5) "aasdf" }
However, what I am getting as output is;
array(1) { [0]=> array(2) { ["index"]=> int(0) ["apikey"]=> string(5) "aasdf" } }
Now, I am aware of the fact that this is easily 'solved' by using $params[0] so i'm not looking for any answers like that.
I'm looking for;
Why does this happen?
Can I count on this to always happen?
Is there something I can do that makes __call receive the original array?
It is expected functionality. Argument $params in the __call method receives the array of parameters method got.
See http://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods for description.
Related
all. I am working on a custom-build API built in PHP. I have an array (see below) that has been returned from my database access object. When I use the json_encode function, the int value assigned to phone1Type gets encoded incorrectly. I have tried this with multiple records, and the value in the encoded json object always matches the phone2Type. Any ideas as to what might be going on? (I've included two sample arrays below in addition to their corresponding json object.)
The code that I'm using to check the array and json values is the following:
$responseObject = $userCtrl->selectPersonForUserId($userId);
var_dump($responseObject);
var_dump(json_encode($responseObject));
One example array to encode is as follows. (The phone1Type and phone2Type keys are at the very end, but include the full array here for completeness. Also, as a side note, the other int values in the array are encoding fine.)
object(Adult)#13 (8) {
["person":protected]=>
object(Person)#14 (4) {
["id":protected]=>
int(3)
["firstName":protected]=>
string(7) "William"
["lastName":protected]=>
string(3) "Smith"
["hasVerified":protected]=>
bool(false)
}
["address":protected]=>
object(Address)#17 (4) {
["id":protected]=>
int(2)
["address1":protected]=>
string(15) "520 Hilbert Dr."
["address2":protected]=>
string(0) ""
["city":protected]=>
object(City)#18 (3) {
["zip":protected]=>
string(5) "71342"
["city":protected]=>
string(11) "West Monroe"
["state":protected]=>
string(2) "AL"
}
}
["email":protected]=>
string(14) "wmrmay#spam.com"
["phone1":protected]=>
string(10) "6195080000"
["phone1Type":protected]=>
int(1)
["phone2":protected]=>
string(10) "3188126574"
["phone2Type":protected]=>
int(0)
["teacher":protected]=>
NULL
}
This encodes to the following json object:
{"person":{"id":3,"firstName":"William","lastName":"Smith","hasVerified":false},"address":{"id":2,"address1":"520 Hilbert Dr.","address2":"","city":{"zip":"71342","city":"West Monroe","state":"AL"}},"email":"wmrmay#spam.com","phone1":"6195080000","phone1Type":0,"phone2":"3188126574","phone2Type":0,"teacher":null}
For brevity, here's the last few lines of another array followed by its json counterpart:
["email":protected]=>
string(20) "wltrallen2#gmail.com"
["phone1":protected]=>
string(10) "6192047586"
["phone1Type":protected]=>
int(1)
["phone2":protected]=>
NULL
["phone2Type":protected]=>
NULL
["teacher":protected]=>
NULL
"email":"wltrallen2#gmail.com","phone1":"6192047586","phone1Type":null,"phone2":null,"phone2Type":null,"teacher":null}
Edited to add original Adult.php model class:
class Adult implements JsonSerializable {
protected $person; // Person object
protected $address; // Address object
protected $email;
protected $phone1;
protected $phone1Type; // PhoneType object
protected $phone2;
protected $phone2Type; // PhoneType object
protected $teacher; // Teacher object
public function __construct($person, $address, $email, $phone1, $phone1Type, $phone2, $phone2Type, $teacher)
{
$this->person = $person;
$this->address = $address;
$this->email = $email;
$this->phone1 = $phone1;
$this->phone1Type = $phone1Type;
$this->phone2 = $phone2;
$this->phone2Type = $phone2Type;
$this->teacher = $teacher;
}
... // Getters and Setters removed for brevity
private function getPhoneType($type) {
if(PhoneTypes::isValid($type)) {
return PhoneTypes::StringDict[$type];
}
return '';
}
function jsonSerialize() {
$array = [
'person' => $this->person,
'address' => $this->address,
'email' => $this->email,
'phone1' => $this->phone1,
'phone1Type' => $this->phone2Type,
'phone2' => $this->phone2,
'phone2Type' => $this->phone2Type,
'teacher' => $this->teacher
];
return $array;
}
}
So, embarrassingly, this was just caused by an initial typo and then forgetfulness on my part.
In the Adult.php model class, I has implemented the JsonSerializable interface to make sure that an Adult object could be encoded in Json. When doing so, I made a typographical error when building the array:
'phone1Type' => $this->phone2Type,
which should have been, of course...
'phone1Type' => $this->phone1Type,
This typo was the source of my issue. Ugh!
However, as I've been deeply mired in this project and it had been some time since I originally built those model classes, I had completely forgot that for an object to be encodable by JSON that it had to implement the JsonSerializable interface. So, as I was debugging, it never occurred to me to look back in my model at the very end of the file to examine the jsonSerialize() function. (Insert face palm here.)
Thank you for your responses. This is the first time that I've actually gotten to post a question on stackOverflow, and I appreciate you all taking a look. Sorry that it wasn't an exciting question and merely a silly novice programmer moment.
I was trying to get a clear difference between methods call_user_func() and call_user_func_array() when I stumbled upon a difference in return types that wasn't apparent to me before.Consider the class Test with a method dnd($t):
class Test {
function dnd($t) {
echo "<pre>";
var_dump($t);
echo "</pre>";
}
}
Instantiate:
$obj = new Test();
$params = [33,22,'fff'];
Now calling by call_user_func method
call_user_func([$obj,'dnd'], $params);
This results in:
array(3) {
[0]=>
int(33)
[1]=>
int(22)
[2]=>
string(3) "fff"
}
While call_user_func_array:
call_user_func_array([$obj,'dnd'], $params);
yields:
int(33)
Why this variation and what impact does it have on parameters passed to functions or function calls that rely on parameters?
call_user_func([$obj,'dnd'], $params)
This resolves to
$obj->dnd(array(33, 22, 'fff'))
while
call_user_func_array([$obj,'dnd'], $params)
resolves to
$obj->dnd(33, 22, 'fff')
In the second parameter call_user_func receives the 'arguments' separately.
So our only argument is the array.
$t = [33,22,'fff']
The second parameter call_user_func_array receives the 'arguments' in the form of an array and sends them to the desired function.
As a result, the first array index is used as the only argument.
$t = int(33) // int(22) and 'fff' are the second and third arguments of the dnd() method (not defined here)
been searching for a solution all day long...
my variable name is $categoryFetchedAsObj
var_dump results :
array(104) {
[0]=>
object(stdClass)#411 (1) {
["categoryHive"]=>
string(4) "asfa"
}
[1]=>
object(stdClass)#412 (1) {
["categoryHive"]=>
string(13) "ENERGY DRINKS"
}
[2]=>
object(stdClass)#413 (1) {
["categoryHive"]=>
string(7) "KETCHUP"
}
[3]=>
object(stdClass)#414 (1) {
["categoryHive"]=>
string(6) "STICKS"
}
and so on
i call a function...
createSelectBlock("category",$categoryFetchedAsObj,"onchange=\"this.form.submit()\"",null,'categoryHive');
here is the instance of the function
createSelectBlock($name,$fetchedNamesAsArrayOfObj,$selectEvent,$objPropertyNameForOptionsValue,$objPropertyNameForOptionsName)
and here is where the error raises
foreach ($fetchedNamesAsArrayOfObj as $rowArrayObj) {
if(isset($objPropertyNameForOptionsValue) && isset($objPropertyNameForOptionsName)){
$selectBlock.="<option value=\"$rowArrayObj->$objPropertyNameForOptionsValue\">$rowArrayObj->$objPropertyNameForOptionsName</option>";
}
if(!isset($objPropertyNameForOptionsValue) && isset($objPropertyNameForOptionsName)){
$selectBlock.="<option value=\"$rowArrayObj->$objPropertyNameForOptionsName \">$rowArrayObj->$objPropertyNameForOptionsName</option>";
}
}
(Object of class stdClass could not be converted to string)
if i replace the
$rowArrayObj->$objPropertyNameForOptionsName
with
$rowArrayObj->categoryHive
everything works but the args of the function are not the same all the time .. obviously
i search this site found some suggestions.. but nothing worked
here is what i tryied
$objPropertyNameForOptionsName='$objPropertyNameForOptionsName';
$rowArrayObj->{'$objPropertyNameForOptionsName'};
any ideas?
after testing and over testing .. finlay i got it working...
this was the correct answer for my situation
if(isset($objPropertyNameForOptionsValue) && isset($objPropertyNameForOptionsName)){
$selectBlock.="<option value=".$rowArrayObj->$objPropertyNameForOptionsValue.">".$rowArrayObj->$objPropertyNameForOptionsName."</option>";
}
if(!isset($objPropertyNameForOptionsValue) && isset($objPropertyNameForOptionsName)){
$selectBlock.="<option value=".$rowArrayObj->$objPropertyNameForOptionsName.">".$rowArrayObj->$objPropertyNameForOptionsName."</option>";
}
hope it helped someone
i am trying to get this working: It is ment to return any function or method where the different 'functional parts' are subgrouped. I have problems with the maybe nested {..{.{} } } function body. At the moment the search breaks of after the first following }.
I do have a little bit a hard time understanding lock arround and recursive handling of Regs. So if someone would like to give a brief overall view - would be great!
i understand enough for this..The Regex:
to work with preg_* in PHP with "/im" set
([\w ]+)?(function)+([\s]+[\w\d]+)([\s]*?\(([^\)]+)?\))([\s]?\{+[^\}]*\})
Here a sample of use (i dont have named subpatterns on this sample...):
<?php
$s=file_get_contents('sometestcode');
$p='/
([\w ]+)?(function)+([\s]+[\w\d]+)([\s]*?\(([^\)]+)?\))([\s]?\{+[^\}]*\})
/im';
$m=array();
preg_match_all($p,$s,$m,PREG_SET_ORDER);
var_dump($m);
?>
Here comes the output as expected:
// Here the subject:
public static private function __set($name,$val){
$this->DATA[$name] = $val;
foreach( /*do it*/ ){
//work it...
}
return $this;
}
// The return
array(6){
[1]=>
string(7) "public static private " //makes sence, ha?
[2]=>
string(8) "function"
[3]=>
string(6) " __set" // func/meth name
[4]=>
string(12) "($name,$val)"
[5]=>
string(10) "$name,$val" // (if passed)$argument...
[6]=>
string(60) "{
$this->DATA[$name] = $val;
foreach( /*do it*/ ){
//work it...
}
// Here is the my link
// How to style the regExpPress??
}"
To clarify:
I'm building a Logger class that allows me to easily log messages:
lib.Logger.php:
<?php
class Logger {
private $handle;
public function __construct($log_name, $log_path) {
if ( ! is_dir($log_path))
throw new Exception('Log path does not exist.');
if ( ! in_array(strtolower(substr($log_name, 0, -4)), array('.log', '.txt')))
$log_name = "{$log_name}.log";
$this->handle = fopen("{$log_path}/{$log_name}", 'a');
$this->log('------------- Initializing ------------- '.get_parent_class($this));
}
// --------------------------------------------------------------------
public function __destruct() {
fclose($this->handle);
}
// --------------------------------------------------------------------
public function log($message) {
$time = date(DATE_RFC822);
$log = "[{$time}] {$message}\n";
fwrite($this->handle, $log);
}
}
?>
And I call this using:
MyController.php:
<?php
class MyController extends Controller {
$logger = new Logger('testlog','/path/to/logs/');
$logger->log('Logs are fun!');
}
?>
When I initialize the object:
$this->log('------------- Initializing ------------- '.get_parent_class($this));
I want to log the name of the object (or file) that is calling log() -- in this case, either MyController or /path/to/MyController.php.
I tried using get_parent_class(), but of course this doesn't work because Logger does not have a parent class per se.
Any ideas? thank you so much for the help!
Alex B
I suppose a solution could be to use debug_backtrace.
The given example gets a backtrace like this :
array(2) {
[0]=>
array(4) {
["file"] => string(10) "/tmp/a.php"
["line"] => int(10)
["function"] => string(6) "a_test"
["args"]=>
array(1) {
[0] => &string(6) "friend"
}
}
[1]=>
array(4) {
["file"] => string(10) "/tmp/b.php"
["line"] => int(2)
["args"] =>
array(1) {
[0] => string(10) "/tmp/a.php"
}
["function"] => string(12) "include_once"
}
}
So, should include what you want ;-)
Still, the solution that seems the best, in my opinion, would be to pass the information needed when calling the log method...
(Just feels more... natural ^^ But that's not a very rational opinion, I suppose ^^ )
You willl need to make use of the function debug_backtrace(). But note that the function is not very consistent in its return value (not every array key is always present, even if it should be - the index file can be missing, for example, indicating that the file is either unknown (eval'd code) or the same as the previous stack frame). The last function that was called before this one should be available at index 0:
$trace = debug_backtrace();
$calling_function = $trace[0]['function'];
The only way to handle this implicitly is to capture the output from debug_backtrace as the others have suggested.
If you are interested in an explicit approach, maybe this could be it
in Logger
public function initialize( $context )
{
$logMessage = '------------- Initializing ------------- ';
if ( is_object( $context ) )
{
$logMessage .= get_class( $context );
} else {
// do something else?
}
$this->log( $logMessage );
}
and then
class MyController extends Controller
{
public function someFunc()
{
$logger = new Logger('testlog','/path/to/logs/');
$logger->initialize( $this );
$logger->log('Logs are fun!');
}
}
I ran into (almost) this exact problem last night. I'm using debug_backtrace() (as many others have already mentioned) to solve it. I needed to know the module that contains the controller that was calling a certain function. Because my controllers contain the module name within the class name, I simply grabbed the return from debug_backtrace() and explode()ed it to fetch the module name.
Soulmerge makes a good point about the return not always being consistent, but if you structure your code a certain way you can definitely get an accurate enough return.