The method is there, but I cannot use it? - php

Fatal error: Call to a member function get() on a non-object on
pr($transaction->invoice->get());
I am getting a weird message. I know for sure the method is there, and is available to use, and even double checked before using it. What's wrong here?
pr(get_class_methods($transaction->invoice));
Array
(
[0] => __construct
[1] => get
[2] => __toString
[3] => getHref
[4] => setHref
[5] => _get
)
Update:
var_dump(is_object($transaction->invoice)); evaluated as bool(true)
None of the methods work. I'm so confused! I think this is one of those edge cases. I'm using Recurly library.
Update
Looks like some objects coming back were un-instantiating themselves. That's weird. I didn't know PHP does this.

What you experience here is Magic. As Magic is so hard to understand, it's even harder to debug. Expect a large chunk of that Recurly PHP library to be based on Magic.
Looks like some objects coming back were un-instantiating themselves. That's weird. I didn't know PHP does this.
It's not PHP, but the library. It makes use of magic getters and setters and other magic stuff for the properties. They must have been driven by some wizard being so much in love with magic. Don't you feel enchanted yet?
Best way to get above the Magic is that you install yourself a step debugger like Xdebug and then set a breakpoint and inspect the values directly. All common PHP IDEs have support for xdebug remote debugging (even this is called remote debugging, it works on your local development machine, too).

Related

Parsing Google Service Objects in PHP

I feel a bit silly, but I have no clue how to parse the objects that Google returns from their API in PHP, can someone shine a light on it?
So for instance, if I request:
print_r($job->getState());
I get this:
Google\Cloud\Scheduler\V1\HttpTarget Object
(
[uri:Google\Cloud\Scheduler\V1\HttpTarget:private] => http://example.com/cron-check.php
[http_method:Google\Cloud\Scheduler\V1\HttpTarget:private] => 1
[headers:Google\Cloud\Scheduler\V1\HttpTarget:private] => Google\Protobuf\Internal\MapField Object...
So how in the world do I get the uri value out of this object?
Googling the Object you're receiving in response, I found the source code for it:
https://github.com/googleapis/google-cloud-php/blob/master/Scheduler/src/V1/HttpTarget.php
Looking at this, there appears to be a simple getter method for the URI property. Try:
$job->getState()->getUri();

What is the best way to troubleshoot this error with parent::find?

I'm trying to build a PHP RESTful service using PhalconPHP. I'm new to PHP, so this may be a beginner question. I am following a tutorial https://www.toptal.com/phalcon/phalcon-php-restful-apis, and in the tutorial there is a section where it makes a call to pull the list of users.
public static function find($parameters = null)
{
return parent::find($parameters);
}
I am passing in a list of parameters listed below.
Array
(
[conditions] =>
[bind] => Array()
[columns] => users_id
)
but I keep getting a 500 error. I'm fairly sure it has to do with how I am connecting (or in this case, NOT connecting to the database).
I'm not 100% sure on what the 'parent' part does either, nor how it connects up to my MySQL database - I think I've gotten the config setup, and I've passed in the tablename that I'm expecting it to be under, but I have no idea if it's actually connecting up and then failing, or if the call itself is failing. So far I've tried echo and print_r with as many variables as I can find, but so far I'm not getting any information on why this is failing.
What is a good way to go about troubleshooting this? How can I find out what the 'parent' is? How can I find out if I'm connecting to my database even, or if it's failing before then?
In your concrete example, the quotes are missing in your conditions and columns parameters, it should be:
$users = Users::find(
[
'conditions' => '',
'bind' => [],
'columns' => "users_id"
]
);
Which should return a list of users ids (if any).
That tutorial from Andrew Belousoff is very good but maybe the next step after Phalcon's REST tutorial, since it explains step by step the inner workings of Phalcon.
For debugging, you can also check Phalcon's guide about it: https://docs.phalconphp.com/en/3.4/debug
And after Belousoff, you can dive into deeper waters with this one: https://github.com/phalcon/phalcon-api
Error 500 means error in php, just check logs. Im not sure how this parent thing is related to phalcon. This is just OOP, you mean you are using framework without knowledge about php/oop? Parent is just parent class which you extends.

Zend Framework partialLoop with associative array of models

I'm making a web application in Zend Framework. I've reached the stage of cleaning up. As things often go, I have a couple of messy view scripts that have become utterly unreadable (tons of (v)sprintf's and loops).
There's one view that's an absolute nightmare... (no/inaccurate comments, shorthand... all things considered to be mortal sins). Just an example:
$rows[$c] .= '<div>'.sprintf('<select id="%s" name="%1$s">',$t.'['.$ref->getCode().']').str_replace('>'.$ref->getCValue().'<',' selected="selected">'.$ref->getCValue().'<','<option>'.implode('</option><option>',$this->vals['P']).'</option>').'</select></div>';
In this particular case, I have an array of models that looks like this:
$arr = array('FOO'=> $Mylib_Model_Person,'BAR'=> $Mylib_Model_Person2);//1~50 mdls
I would like to use a partial loop, but there's a problem:
$this->partialLoop('controller/_myPartial.phtml',array('model'=>$arr));
//in the partial loop:
Zend_Debug::dump($this->m);
I see all my models correctly, but their keys have all been turned into properties.
$this->FOO->someMethod();//works fine
Bur I want it to be:
<span><?php echo $key; ?></span><span><?php echo $model->someMethod(); ?></span>
I've also tried using $this->partialLoop()->setObjectKey('Mylib_Model_Person');, but that didn't seem to make any difference, other then confuse me.
The only solutions I see is either array_map, but that would defeat the point (I'm trying to end up with a clean view script); or rewrite a part of my service layer, to return the data ready structured, and keep the array_map there.
I can't help thinking that what I want to do, essentially use a partialLoop as an array_map callback, is possible. If it isn't, is there an alternative? Any thoughts?
I've tried get_object_properties($this), and iterate through the object properties, to no avail, the loop simply doesn't get executed(?!)
As it turns out $this->partialLoop()->setObjectKey('Mylib_Model_Person'); should have been $this->partialLoop()->setObjectKey('model');. If I do change this, and start the partial loop by dumping $this->model, I see my model. However:
echo $this->model->someMethod(); //throws error: method on non-object
Zend_Debug::dump(get_class_methods($this->model));//shows all methods, including someMethod()
And to add insult to injury, tears and confusion. The model implements the toArray-thing, so I tried:
echo $this->model['someData'];//Error: cannot use object of type Mylib_Model_Person as array!!
So, it's not an object when I try to use methods, it's an object when trying to access data as an array, and when using the magic getter method ($this->model->some_Data) it doesn't do anything. No errors, but no output either. The view is rendered as is.
I'm thinking I ran into a bug. I'll rapport it. Consider this:
$methods = get_class_methods($this->model);
while($m = array_shift($methods))
{
if (substr($m,0,3) === 'get')
{
Zend_Debug::dump($m);//e.g getName
Zend_Debug::dump($this->model->{$m}());//'Foobar'
$m = 'someMethod';//copy-paste, so typo's aren't to blame
Zend_Debug::dump($this->model->{$m}());//'the data I was after'
}
}
So that works, but the, if I try:
$this->model->{'someMethod'}();//Error again
//or even:
$m = 'someMethod';
echo $this->model->{$m}();//Error...
That can't be right
I found out what the problem was. Our development server used to be set up better in terms of error reporting:
I assumed E_ALL | E_STRICT, but I had a look only to find it changed to a cruddy E_COMPILE_ERROR | E_ERROR | E_CORE_ERROR. Seeing as some values in the array can be false rather then an object, at some point in the partialLoop script, a notice should have been raised - with the correct ini settings, of course.
That was the cause of the unexpected behaviour; that, and a silly bug or two.

__PHP_Incomplete_Class_Name wrong

We're randomly getting some very strange error logs. They don't happen on every page hit, even with the same parameters/actions/etc, and they don't seem repeatable, each one is different in its crash location, and context. But almost all have incorrect __PHP_Incomplete_Class_Name as the cause.
One such error is:
main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "LoginLogging" of the object you are trying to operate on was loaded before unserialize() gets called or provide a __autoload() function to load the class definition
The problem being, there is no "LoginLogging" class. The object it's referring to was of type ScormElement when it was saved into the session.
Doing a dump of the variable gives:
__PHP_Incomplete_Class::__set_state(array(
'__PHP_Incomplete_Class_Name' => 'LoginLogging',
'intUserId' => '64576',
'__intUserId' => '64576',
'intScormId' => '665',
'__intScormId' => '665',
'intScoId' => '9255',
'__intScoId' => '9255',
'strElement' => 'cmi.core.lesson_location',
'__strElement' => 'cmi.core.lesson_location',
'strValue' => '1',
'dttTimeModified' => QDateTime::__set_state(array(
'blnDateNull' => false,
'blnTimeNull' => false,
'strSerializedData' => '2011-08-31T08:05:22-0600',
'date' => '2011-08-31 08:05:22',
'timezone_type' => 1,
'timezone' => '-06:00',
)),
'__strVirtualAttributeArray' => array (),
'__blnRestored' => true,
'objUser' => NULL,
'objScorm' => NULL,
)
All the properties are retained correctly, and match the class definition for ScormElement. But the class name is wrong. There is no class named LoginLogging.
What is causing this and how do we fix it???
Edit: This is just an example. Other errors are very similar in structure, but affect other class types, and have different incomplete names. However, ALL incomplete names have the same string length of the correct class name.
Edit 2011-10-27: I'm still seeing these error logs, and have had no success in finding a solution. Any help would be appreciated.
PHP 5.3.3, APC, default session handler.
As written in the quote in your question __PHP_Incomplete_Class_Name is a special class name in PHP that is used whenever the class definition could not be found when unserializing (unserialize()).
It's suggested to either ensure the class definition is available or to provide some autoloading for the missing class.
You commented that PHP is looking for the wrong classname here:
wrong: LoginLogging
right: ScormElement
It's hard to say with the information given why the classname is being changed on serialization/unserialization. The information you've given (especially the dump) in your question is incomplete.
So the options are limited to some general suggestions:
You could inspect the serialized string which classname is given in there so you could at least say if it happens with serialization or unserialization. You can easily inspect serialized data with the Serialized PHP Library which has a text-dumper for debug purposes.
Additionally there is the unserialize_callback_func Ini-Directive you can use to further trace the problem.
<?php
$serialized_object='O:1:"a":1:{s:5:"value";s:3:"100";}';
// unserialize_callback_func directive available as of PHP 4.2.0
ini_set('unserialize_callback_func', 'mycallback'); // set your callback_function
function mycallback($classname)
{
// just include a file containing your classdefinition
// you get $classname to figure out which classdefinition is required
}
As you write the problem does not occur any longer, I suspect that at some point the serialization on your site was broken storing invalid data. Which framework/libraries/application are you using? Which component takes care about serialization?
If your trying to access a property method of an object or serialized value you've stored in a $_SESSION variable and you included the class after calling session_start() try including the class before calling session_start();
This happens when we try to initialize the session before loading the class definitions for the object we are trying to save into the session.
you can use simply json methods in PHP
json_encode that array and again json_decode that array and save it in a variable and than print that variable. you will get a simple array.
eg.
$array = array(); // this is your array variable to whom you are trying to save in a session
$encode = json_encode($array);
$decode = json_decode($encode);
echo '<pre>';
print_r($decode);
it will work surely.
Are you, by any chance, using some opcode cache (e.g. APC, XCache) or some debugger? They sometimes cause weird things to happen. If there isn't and never was a LoginLogging class in your project, but yours is not the only project on the server, I would bid on the cache.
To include the class before the session_start() works fine for me. =)
Hakre's suggestion to look at session_write_close led me to what appears to be a reliable fix:
register_shutdown_function('session_write_close');
This forces the session to be written out before any memory cleanup and class unloading occurs. This is important due to a change in PHP that can result in a race condition between APC removing class references and PHP writing out the session data: http://news.php.net/php.internals/46999
When you try to unserialize a variable, php must know the structure of the object. Try to include your class before unserialize. Which class? the one that holds those properties shown in your code. include('pathtoyourclass/classname.php') or include_once('pathtoyourclass/classname.php').
Good luck!
I use this function to solve this problem
$user = $_SESSION['login'];
$auth_user= fixObject($user);
function fixObject(&$object) {
if (!is_object($object) && gettype($object) == 'object')
return ($object = unserialize(serialize($object)));
return $object;
}
It is the serialization issue in your code.It may be your code for some reason could not initialize the object and in next part of your code tries to convert that object to string or some other data type.
Just inspect your code, properly initialize your objects.
Check if you are using serialize()/unserialize() method.
Are you receiving this serialized object from a service/stream or reading it from a file? I've seen it happen in a client-server setting the client side object and the server side objects differ very slightly... maybe have a property that the other doesn't have. This also happens when you serialize an object, save it to file, then refactor code that removes a class and then try's to deserialize the object.
Then when it gets deserialized and tries to instantiate the needed classes they don't exist.
The error is clear and straightforward, you're creating a object for which the class has not been loaded.
I'd do a string search on your code, find where the needed class is located, and make a simple autoloader (or just a raw include/require) of the file. Just get the class it needs loaded somehow.
If the class really doesn't exist anywhere, try checking earlier revisions (I'm assuming you have version control of some type) for existence of the class. If you're deserializing an object generated by another system check that system out as well.

Best performance for loading settings in PHP?

My latest idea for do settings across my php project I am building was to store all my settings in a config PHP file, the php file will just return an array like this...
<?php
/**
* #Filename app-config.php
* #description Array to return to our config class
*/
return array(
'db_host' => 'localhost',
'db_name' => 'socialnetwork',
'db_user' => 'root',
'db_password' => '',
'site_path' => 'C:/webserver/htdocs/project/',
'site_url' => 'http://localhost/project/',
'image_path' => 'C:/webserver/htdocs/fproject/images/',
'image_url' => 'http://localhost/project/images/',
'site_name' => 'test site',
'admin_id' => 1,
'UTC_TIME' => gmdate('U', time()),
'ip' => $_SERVER['REMOTE_ADDR'],
'testtttt' => array(
'testtttt' => false
)
);
?>
Please note the actual config array is MUCH MUCH larger, many more items in it...
Then I would have a Config.class.php file that would load my array file and use the magic method __get($key). I can then autoload my config class file and access any site settings like this...
$config->ip;
$config->db_host;
$config->db_name;
$config->db_user;
So I realize this works great and is very flexible, in my class I can have it read in a PHP file with array like I am doing now, read INI file into array, read XML file into array, read JSON file into array. So it is very flexible for future projects but I am more concerned about performance for this particular project that I am working on now, it will be a social network site like facebook/myspace and I have had one before prior to this project and once I got around 100,000 user's performance became very important. So I am not "micro-optimizing" or "premature optimizing" I am stricly looking to do this the BEST way with performance in mind, it does not need to be flexible as I will only need it on this project.
So with that information, I always read about people trying to eliminate function calls as much as possible saying function calls cause more overhead. SO I am wanting to know from more experienced people what you think about this? I am new to using classes and objects in PHP, so is calling $config->db_user; as costly as calling a function in procedural like this getOption('db_user'); ? I am guessing it is the same as every time I would call a setting it is using the __get() method.
So for best performance should I go about this a different way? Like just loading my config array into a bootstrap file and accessing items when I need them like this...
$config['db_host'];
$config['db_username'];
$config['db_password'];
$config['ip'];
Please give me your thoughts on this without me having to do a bunch of benchmark test
From tests I've seen, I believe Alix Axel's response above is correct with respect to the relative speed of the four methods. Using a direct methods is the fastest, and using any sort of magic method usually is slower.
Also, in terms of optimization. The biggest performance hit for any single request in the system you describe will probably be the parsing of the XML/INI/JSON, rather than the accessing of it via whichever syntax you decide to go with. If you want to fix this, store the loaded data in APC once you parse it. This will come with the one caveat that you will want to only store static data in it, and not dynamic things like the UTC date.
Firstly, instead of an included file that returns an array I would instead use an .ini file and then use PHP's parse_ini_file() to load the settings.
Secondly, you shouldn't worry about function calls in this case. Why? Because you might have 100,000 users but if all 100,000 execute a script and need some config values then your 100,000 function calls are distributed over 100,000 scripts, which will be completely irrelevant as far as performance goes.
Function calls are only an issue if a single script execution, for example, executes 100,000 of them.
So pick whichever is the most natural implementation. Either an object or an array will work equally well. Actually an object has an advantage in that you can do:
$db = $config->database->hostname;
where $config->database can implicitly load just the database section of the INI file and will create another config object that can return the hostname entry. If you want to segment your config file this way.
IMO these are the fastest methods (in order):
$config['db_user']
$config->db_user directly
$config->db_user via __get()
getOption('db_user') via __get()
Also, you've already asked a lot of questions about your config system, not that I mind but I specifically remembered that you asked a question about whether you should use parse_ini_file() or not.
Why are you repeating the basically same questions over and over again?
I think you're taking premature optimization to a whole new level, you should worry about the performance of 100,000 users iff and when you get 50,000 users or so, not now.

Categories