简体   繁体   中英

PHP function param type best practices

I am currently working on a framework and have come accros a snag... how should I handle incorrect parameter types when someone calls a function in the framework?

Example:

// Title is expected to be string, comment_num is expected to be int
function example1($title, $comment_num) {


 // Doesnt throw error, just converts type 
 $title = (string) $title;
 $comment_num = (int) $comment_num;

}

or

// Title is expected to be string, comment_num is expected to be int

function example2($title, $comment_num) {


 if (!is_string($title)) {

  trigger_error('String expected for first parameter', E_USER_WARNING);
  return;
 }

 if (!is_string($title)) {

  trigger_error('Int expected for second parameter', E_USER_WARNING);
  return
 }
}

Or would a mixture of both work? Throw an error and convert the type anyway?

What would be the best way of doing this? I plan on releasing it so it's not just going to be me using it, therefore I want to think of the best way for others as well. Thanks.

EDIT!!!

So I decided to give the answer but i also wanted to post the code i made which allows me to quickly check types. Its abit rough but it works well enough.

function __type_check($params) {

    if (count($params) < 1) {

        return; 
    }
    $types = func_get_args();
    array_shift($types);

    $backtrace = debug_backtrace();
    $backtrace = $backtrace[1];

    $global_types = array(
        'bool'  => 'boolean',
        'int'   => 'integer',
        'float' => 'double' 
    );

    $error = false;


    for ($i = 0, $j = count($types); $i < $j; ++$i) {

        if (strpos($types[$i], ',') === false) {

            $type = strtolower($types[$i]);

            if (isset($global_types[$type])) {

                $type = $global_types[$type];
            }

            if (gettype($params[$i]) != $type) {
                $error = true;
                break;
            }

        } else {

            $current_types = array_map('trim', explode(',', $types[$i]));

            foreach ($current_types as $type) {

                $type = strtolower($type);  

                if (isset($global_types[$type])) {

                    $type = $global_types[$type];
                }

                if (gettype($params[$i]) == $type) {

                    continue 2; 
                }
            }

            $error = true;
            break;
        }       
    }

    if ($error) {
        trigger_error($backtrace['function'] . '() expects parameter ' . ($i + 1) . ' to be ' . $types[$i] . ', ' . gettype($params[$i]) . ' given', E_USER_WARNING);
        return false;
    }

    return true;
}

And you would use it like this:

function string_manipulation($str, $str2, $offset = 1) {

    if (!__type_check(func_get_args(), 'string', 'string', 'int,float')) {

        return false;   
    }   

    // do manipulation here
}

That would basically check that the first and second parameters are strings, and the 3rd parameter is an integer or a float. You can combine any types 'string,int,array,object' etc and all valid types are taken from gettype

/* Known bugs */ null is a type, cant decide on if it should be or not if you enter a class name, it doesn't check instance of but just does typecheck havent figured out a good way to trigger the error... meh

Thats it from me, the bugs can be easily fixed :D

It depends.

PHP is a dynamically typed language, and sometimes for a good reason. Since it deals a lot with HTTP data, which is all strings all the time, numbers aren't necessarily always of type int and will still work fine for general operations.

Strictly enforcing primitive types is often very un-PHPish and could be a hassle to work with.

The usual way to do things in PHP is to accept arguments in almost any type and work with them in good faith until you need to have specific results or the type becomes an issue.

function example1($title, $comment_num) {

    // do some operations that should work error-free regardless of type

    if ($result != 'something specific you expect here') {
        throw new Exception('Something went wrong!');
        // or
        trigger_error('Something went wrong!');
        return false;
    }

    // continue with $result
}

You can go the OOP route and construct objects this way. Objects will be flexible to some degree in what they accept. If they succeed in being constructed, you have a defined object of a specific type that you can use for PHP-enforced type hinting:

function example1(TitleObject $title) {
    // rest assured that $title is of the right type
}

If anything, just use SPLTypes and be done; otherwise throw InvalidArgument exceptions

I would typecast the int and string datatypes automatically with no complaint (because they could be easy to mix up), but for something like a resource or object it could be a useful feature to notify the programmer of an error.

I would also set up the notification code in its own function so things wouldn't get so repetitive. Anyways, Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM