views:

545

answers:

8

Is there any way to force PHP to blow up (error, whatever) if I misspell a variable name? What about if I'm using an instance of a class and I spell the name of a variable wrong?

[I know that I should just get used to it, but maybe there's a way to enforce name checking?]

Thanks!

Edit: Sorry, that wasn't very specific. Here's the code, and I would like to get two errors. Right now I only get one (for the last line).

error_reporting(E_ALL|E_STRICT);
class Joe {
    public $lastName;
}

$joe = new Joe();
$joe->lastNombre = "Smith";
echo "And here it is " . $jose;
+1  A: 

You can use this in your code:

error_reporting(E_ALL);

or this in php.ini

php_error_reporting=5

http://us2.php.net/error_reporting

Ryan Doherty
+2  A: 

You could try:

error_reporting(E_ALL|E_STRICT);

EDIT: OK, I've now read the updated question. I think you're out of luck. That's valid in PHP. Some say it's a feature. :)

PEZ
I'll be trying that in a few seconds...
Yar
Check the edit on the question, if you will... thanks!
Yar
+1  A: 

Setting error_reporting to include E_NOTICE may help somewhat. It has a tendency to display a notice/error whenever you use a undefined variable(note that it doesn't stop the execution).

Marek
Yeah, I don't need it to stop execution, it's for dev, not for production, if you will...
Yar
+2  A: 

From the PHP docs on error_reporting:

// Reporting E_NOTICE can be good too (to report uninitialized
// variables or catch variable name misspellings ...)
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
Paolo Bergantino
right but it will not do it for a variable on an obj
Yar
+4  A: 

Here is something I whipped up really quickly to show how you can trigger errors when something like that happens:

<?php

error_reporting( E_ALL | E_STRICT );

class Joe {
    public $lastName;

    public function __set( $name, $value ) {
        if ( !property_exists( $this, $name ) ) {
            trigger_error( 'Undefined property via __set(): ' . $name, E_USER_NOTICE );
            return null;
        }
        $this->$name = $value;
    }

    public function __get( $name ) {
        if ( !property_exists( $this, $name ) ) {
            trigger_error( 'Undefined property via __get(): ' . $name, E_USER_NOTICE );
            return null;
        }
        return $this->$name;
    }
}

$joe = new Joe();
$joe->lastNom = "Smith";
echo $joe->lastNom , "\n";

?>
Nick Presta
Calling property_exists() is unnecessary because the magic method wouldn't be called in the first place if the property exists
monzee
I realize in this example that is the case but if you're using __set() and/or __get() for private members, the magic methods are called. *shrug*
Nick Presta
Your implementation of __set() is broken: $name = $value should be $this->$name = $value; (however I would actually leave that line out). Also, __get() is broken, too: return $name should be return $this->$name, but again I wouldn't actually put that in there.
too much php
Thanks Nick, but I'm just trying to get error-free code, not create more! Vote up for verbosity and effort, though!
Yar
Upvoted on faith you'll fix the code so that it works.
Justin Poliey
Sorry about that. I was on my way out and quickly threw that together. Fixed the errors Peter mentioned. :)
Nick Presta
The getters/setters should perhaps get/set something too? =) Other than that, this is the answer I would have written.
gnud
I'm not following (to to ignorance perhaps): those gets and sets automatically fire in the sample code you provide at the bottom?
Yar
@Rosenstark, yes, see http://www.php.net/manual/en/language.oop5.overloading.php -- the point is to show that a typo (lastNom instead of lastName) would cause an E_NOTICE to be "thrown," which most likely results in a message in the output.
strager
Hmm. I wonder why this was voted down. Is there anything you would like me to change?
Nick Presta
Hey Nick, I personally voted it up. It's fascinating, though I'm amazed on a daily basis by how annoying PHP is.
Yar
@Nick, you should precise that __get/__set is called ONLY when the accessed property is not visible or simply does not exist. for instance, if you had a private $lastNom property in your class, no E_NOTICE would be raised. In your example, however, since you have a return null after your trigger_error, your __get/__set 's return statement will never get executed :)
Yanick Rochon
A: 

A soultion could be to always use getters and setters. But offcoursE: you have to write the getters correctly. So maybe Nick Prestas answer is the best! ;-)

qualbeen
A: 

To catch the undeclared property you can set your _ _Set() magic method to catch them

function __set($sKey, $sValue)
{
   // any setter data should be *returned* here

   // NOTE: this function will only get called if the property is not
   // publicly accessible.
   trigger_error("Non-existing property name ".$sKey, E_USER_WARNING);
}
null
thanks! Nick's answer pretty much covers that.
Yar
+1  A: 

Know this is an old post - but stumbled across it looking for a solution.

This is my final solution:

I have an abstract class that my classes extend that throws an error on magic __get and __set.

It's nasty - but it works a treat!

It's similar to suggestions above - but have also added 'final' to the method declaration to stop people overwriting it.

We also use a code sniffer to catch these - but I wanted to get my error messages 'live' as I coded, instead of having to wait for a report from the sniffer. (Also people can ignore sniff reports!)

Sample code below

   <?php
/**
 * Abstract
 * Some default Abstract functions that everything should extend
 *
 * @package    example
 * @subpackage lib
 */

/**
 * Class mh_abstract
 * Some default MH Abstract functions that everything should extend
 *
 * @package    example
 * @subpackage lib
 */
abstract class lib_abstract
{
    /**
     * Throws an error if php magic set is called
     *
     * @param string        $key
     * @param string|object $value
     *
     * @throws Exception When trying to set a new class property
     */
    final public function __set($key, $value)
    {
        // get if the thing we are trying to set is a object
        if(is_object($value))
        {
            // if so let's just report it's name, not the full object
            $value = 'object:'.get_class($value);
        }

        // throw the error!
        throw new mh_lib_error_dev_unknownClassProperty('Tried to set new property '.$key.' with value '.$value);
    }

    /**
     * Throws an error if php magic get is called
     *
     * @param string $key
     *
     * @throws Exception When trying to set a new class property
     */
    final public function __get($key)
    {

        // throw the error!
        throw new mh_lib_error_dev_unknownClassProperty('Tried to get new property '.$key);
    }
}
Alec
I haven't looked at PHP in so long that I can no longer evaluate this quickly. +1 for now. If I can get some more feedback on this I could mark it best answer.
Yar