using Programming;

A Blog about some of the intrinsics related to programming and how one can get the best out of various languages.

Getting started with PHP: Part 3

Getting started with PHP: Part 3

Previously, we discussed some more of the fundamental components of PHP:

  • Strings have 4 ways to be built;
  • Magic superglobals: $_POST and $_GET;
  • Basic arrays;
  • Creating and calling functions;
  • Logical combination operators (&&, ||, !, xor);

We also discussed some bits of HTML:

  • Forms;
  • Input types: text, textarea, checkbox, radio, select;

More Function Bits

We touched on functions last time, but we have so much more to cover in that area alone. Functions in PHP are extremely powerful, and there are a lot of features I want to cover so that you are familiar with them.

PHP: Default Values for Function Parameters

One of the features of PHP functions is the ability to specify default values for parameters. This means we can build functions that have values we may or may not need to provide.

PHP accomplishes this in a rather simple, and self-explanatory manner: simply add an equal sign (=) and then the default value after the parameter name:

function greet(string $name, bool $all_caps = FALSE): string {
    if ($all_caps) {
        $name = strtoupper($name);
    }
    return "Hello $name";
}

We can call our function with or without the optional values:

$name = "Elliott";
echo greet($name) . "<br />"; // "Hello Elliott"
echo greet($name, FALSE) . "<br />"; // "Hello Elliott"
echo greet($name, TRUE) . "<br />"; // "Hello ELLIOTT"

As we see, just providing $name is equivalent to providing FALSE for the second value because of our default specification.

Normally, I would advise against default values, but with PHP sometimes it becomes necessary. Many languages have something called "overloading", where you can create more than one function with the same name but different parameter, but PHP does not have that feature, so we use optional parameters with default values instead.

PHP: Late-defined Functions

PHP supports the idea of defining functions after another function is called. This is either nesting functions, or late-defined functions. The functions don't exist initially, but can be created after another function is called.

Doing this is rather straightforward, simply define the function you want to be created within another function.

function f1() {
    function f2() {
        echo "Test";
    }
}

In this example, function f2 does not exist until f1 is called.

I've never seen much usage of this feature in the past, but I think it's important to talk about because if you do see this I want it to look familiar.

PHP: Variable-length Arguments

Another feature of PHP is variable-length arguments, or, indicating that the function can take any number of parameters.

The method for doing this is to specify three dots before the final parameter: ...$values.

function sum(int ...$values): int {
    $result = 0;
    foreach ($values as $value) {
        $result += $value;
    }
    return $result;
}

The variable will be treated in the function as an array, but the type should be specified as the plain type of the data. Here, we specified we expect an int, then that any number of integers can be provided.

This can be called in two ways: separate each value with a comma, provide an array and use the same triple-dot to pass it:

echo sum(1, 2, 3, 4) . "<br />";
echo sum(...[1, 2, 3, 4]) . "<br />";

PHP: Accessing global variables in functions

Once you start playing with functions, you might find that there's a certain task that becomes problematic: accessing global (not superglobal) variables within a function.

As an example, imagine we have a function that works on a user:

$user_id = 1;
$user_name = "Elliott";
function is_user_valid() {
    return $user_id !== 0 && $user_name !== "";
}
echo is_user_valid() . "<br />";

If you run this, you will get two errors:

Notice: Undefined variable: user_id in $file on line $line

Notice: Undefined variable: user_name in $file on line $line

This is telling us that, while our code looks reasonable, PHP can't access $user_id or $user_name in the function.

This is because those variables are globals, and we have to tell our function how to access them.

PHP: Scoping

PHP has a concept of "scoping", or: data is only available to the scope it is in, or a scope within that scope. We can see this with the function example above: the curly-braces ({}) create a new scope, and we lose access to certain things.

The "global" scope is a special scope in PHP, and anything that is not in a class (we'll talk about those later) or function is part of this "global" scope. This means our $user_id and $user_name variables are in the "global" scope.

Beyond that, PHP scopes at the namespace, class and function levels. Classes can only access other classes in the same namespace or a parent by default, functions can only access data in that function or class by default. This means that to share data between functions or classes you have to pass that data from one to the other.

Back to Accessing the Globals

So, with that said, we need to find a way to access those two variables within our function. One method would be to pass them in, and 99% of the time that is the method you should choose, but we're going to see how we can avoid that.

The first way to pull global values into our local function is to use the global keyword and then name the variables that are defined in the global-scope. In our example, we would do the following:

function is_user_valid() {
    global $user_id, $user_name;
    return $user_id !== 0 && $user_name !== "";
}

Here, global $user_id, $user_name; says that those two variables are pulled from the global scope. I prefer this method if I must access global values, as it feels the cleanest, and with the IDE I use (PhpStorm, if anyone is curious) I get auto-completion for them.

The next method is to use another special superglobal called $GLOBALS (yes, quite "on the nose"). This superglobal takes a string index like an array, which is the variable name (without the dollar-sign in front of it): $GLOBALS["user_id"] and $GLOBALS["user_name"].

This would leave us with the following function:

function is_user_valid() {
    return $GLOBALS["user_id"] !== 0 && $GLOBALS["user_name"] !== "";
}

I'm not a huge fan of this method, I prefer the global <names> method if I must use globals in a function, but once again I want you to be aware of all the options out there.

PHP: Let's talk about some built-in functions

So, we've talked about how we can write our own functions, I think it's time we talk about some built-in PHP functions.

One thing I want to mention: PHP didn't always have a naming-convention, so some PHP functions are what we call "snake case": snake_case, some are "all lower letters" alllowerletters. This can be confusing at times, but it's mostly because PHP grew organically.

What do I mean by "organically"? In the early days, PHP only added things when they were needed. Instead of trying to over-engineer the language, functions were added by the people who needed them when they were needed, and because there was no naming convention they were named by the people who needed them.

As a result of this, you might find that function names don't always seem consistent. This is a common gripe of various communities, both PHP-oriented and not. Some folks like to use it as an excuse to talk trash about PHP, but it's just a by-product of PHP being one of the early languages to allow the users of the language to commit back to it.

PHP is a very string-oriented language, which makes sense because it's primarily a web language, and strings are the language of the web. So, as a result, we're going to talk about a lot of string-related functions.

PHP: Functions for Arrays and Strings

There are three major string/array functions in PHP I want to talk aboue:

  1. explode - split a string on characters;
  2. implode - combine an array of strings with a delimiter;
  3. str_split - split a string into groups of characters;

So explode and implode are basically opposites of each other: one turns a string into an array, the other turns an array into a string. Both use some sort of "delimiter" to split or combine on.

The syntax for each is rather straightforward: explode(string $delimiter, string $string): array, implode(string $separator, array $array): string.

Additionally, implode does not require the $separator to be provided, instead it can be omitted and the string will be concatenated with no separators.

We'll go through a quick example of explode and implode to see how they work:

$my_name = "Elliott";
$some_str = "Hello $my_name, how are you doing?";
echo $some_str . "<br />";
// Hello Elliott, how are you doing?

$parts = explode(" ", $some_str);
print_r($parts);
echo "<br />";
//Array (
//    [0] => Hello
//    [1] => Elliott,
//    [2] => how
//    [3] => are 
//    [4] => you
//    [5] => doing?
//)

$some_str = implode(" ", $parts);
echo $some_str . "<br />";
// Hello Elliott, how are you doing?

Right, so next we'll discuss str_split really quick. I'll admit, the name on this one isn't exactly self-explanatory, but what it does is split a string into groups of characters with a specified length.

$str_groups = str_split($some_str, 3);
print_r($str_groups);
echo "<br />";
//Array
//(
//    [0] => Hel
//    [1] => lo
//    [2] => Ell
//    [3] => iot
//    [4] => t, 
//    [5] => how
//    [6] =>  ar
//    [7] => e y
//    [8] => ou
//    [9] => doi
//    [10] => ng?
//)

As we see, the string split into groups of 3 characters. This function is handy if you have block-data that you need to group up, such as hexadecimal values. Such as: str_split("0x1234", 2) will split into ["0x", "12", "34"].

There is another method for splitting strings in PHP, but we're not going to discuss it yet because it involves regular expressions, and I want to cover those at a later date.

PHP: Trimming Strings

The first three functions I want to talk about are ltrim, rtrim and trim. All three of these functions have a similar goal: they remove whitespace characters (or, if you choose, a group of characters you specify) from the beginning, end, or both of a string.

The ltrim function removes characters from the beginning, the rtrim function from the end, and trim is effectively ltrim(rtrim($value)).

$str = "  Test String with Whitespace  ";
$str_l = ltrim($str); // "Test String with Whitespace  "
$str_r = rtrim($str); // "  Test String with Whitespace"
$str_t = trim($str); // "Test String with Whitespace"

Additionally, all three take a second "mask" parameter:

$str = "123Test String with Whitespace321";
$mask = "123";
$str_l = ltrim($str, $mask); // "Test String with Whitespace321"
$str_r = rtrim($str, $mask); // "123Test String with Whitespace"
$str_t = trim($str, $mask); // "Test String with Whitespace"

The "mask" is just a string with every character you want to trim from the beginning / end. You'll also notice that the mask doesn't need to be in any particular order: ltrim / rtrim / trim will use it to build a list of characters to remove.

PHP: Searching Strings

PHP has quite a few functions for searching strings. The main ones we'll discuss are: strstr, stristr, strpos, stripos, strrpos, strripos, substr, substr_count. Note: I left the regular-expression based functions out again, as these are going to be covered later.

The first two functions we'll discuss are strstr and stristr. Both of these find a string within another string (thus, searching for a str in a str, hence the name strstr). The only difference is that stristr is case-insensitive. Both of these return either the string + everything after it, or if you specify the value TRUE for the optional parameter $before_needle it will return the part before the located string:

$my_name = "Elliott";
$some_str = "Hello $my_name, how are you doing?";
$result = strstr($some_str, $my_name); // "Elliott, how are you doing?"
$result = strstr($some_str, $my_name, TRUE); // "Hello "

One last note: both of these will find the first occurrence of the search.

The next functions I want to discuss are strpos, stripos, strrpos, strripos. The strpos function is the same as strstr, with the exception that it returns the position of the string it located, rather than returning the string. The strrpos function does the same, except it searches the string backwards.

All of these also take an optional integer parameter that indicates where to start searching the string. If the integer is greater than 0, it will start searching at that many characters from the beginning of the string. If the number is negative, it will start searching from that many characters from the end of the string.

$result = strpos($some_str, $my_name); // 6
$result = strrpos($some_str, $my_name); // 6

The stripos and strripos are the case-insensitive versions.

Next, we have substr, which will return a part of a string from a position for a given length. If the $length parameter is not provided then the entire string from the start position to the end will be returned.

$result = substr($some_str, 6); // "Elliott, how are you doing?"
$result = substr($some_str, 0, 5); // "Hello"

Lastly, substr_count, which will search a string for another and return how many times it appeared.

$result = substr_count($some_str, $my_name); // 1

PHP: Basic string manipulation

There are some basic manipulation functions I want to talk about, things that are relatively simple. I want to go over strrev, str_rot13, wordwrap, lcfirst, ucfirst, ucwords, strtolower, strtoupper.

The first function on the list, strrev, is a function that reverses a given string. The str_rot13 function rotates the letters of the string by the ceaser cipher, with a => n, m => z.

$result = strrev($some_str); // "?gniod uoy era woh ,ttoillE olleH"
$result = str_rot13($some_str); // "Uryyb Ryyvbgg, ubj ner lbh qbvat?"

The wordwrap function will wrap the string on words to be no longer than the given width. There are three optional parameters: the first is the maximum width of a line in characters and defaults to 75, the second parameter is a string separator to use and defaults to "\n", the third and final parameter is whether or not to cut up long words and defaults to FALSE.

$result = wordwrap($some_str, 10); // "Hello\nElliott,\nhow are\nyou doing?"

Next, lcfirst and ucfirst both change the case of the first character in the string. The lcfirst function will make it a lower-case character, and the ucfirst function will make it an upper-case character.

$result = lcfirst($some_str); // "hello Elliott, how are you doing?"
$result = ucfirst($some_str); // "Hello Elliott, how are you doing?"

The ucwords function changes the case of the first letter of each word to upper-case.

$result = ucwords($some_str); // "Hello Elliott, How Are You Doing?"

Lastly, in this group, we have strtolower and strtoupper, which convert the entire string to all lower-case or all upper-case respectively.

$result = strtolower($some_str); // "hello elliott, how are you doing?"
$result = strtoupper($some_str); // "HELLO ELLIOTT, HOW ARE YOU DOING?"

PHP: String Hashing

PHP includes a pretty large quantity of functions built to hash strings. Note: none of the ones we are discussing in this section are suitable for passwords, we will discuss password-hashing on its own at a later date.

We're going to discuss all these as a group, as the only major differences in them are the particular algorithm.

While the string hashing functions we're talking about are not suitable for hashing passwords, they are suitable for data validation and message digest validation.

The hash algorithms supported by PHP can be determined by using the hash_algos() function. You can print_r this function if you need a quick list for reference. The list my computer generated is as follows:

//Array
//(
//    [0] => md2
//    [1] => md4
//    [2] => md5
//    [3] => sha1
//    [4] => sha224
//    [5] => sha256
//    [6] => sha384
//    [7] => sha512/224
//    [8] => sha512/256
//    [9] => sha512
//    [10] => sha3-224
//    [11] => sha3-256
//    [12] => sha3-384
//    [13] => sha3-512
//    [14] => ripemd128
//    [15] => ripemd160
//    [16] => ripemd256
//    [17] => ripemd320
//    [18] => whirlpool
//    [19] => tiger128,3
//    [20] => tiger160,3
//    [21] => tiger192,3
//    [22] => tiger128,4
//    [23] => tiger160,4
//    [24] => tiger192,4
//    [25] => snefru
//    [26] => snefru256
//    [27] => gost
//    [28] => gost-crypto
//    [29] => adler32
//    [30] => crc32
//    [31] => crc32b
//    [32] => crc32c
//    [33] => fnv132
//    [34] => fnv1a32
//    [35] => fnv164
//    [36] => fnv1a64
//    [37] => joaat
//    [38] => haval128,3
//    [39] => haval160,3
//    [40] => haval192,3
//    [41] => haval224,3
//    [42] => haval256,3
//    [43] => haval128,4
//    [44] => haval160,4
//    [45] => haval192,4
//    [46] => haval224,4
//    [47] => haval256,4
//    [48] => haval128,5
//    [49] => haval160,5
//    [50] => haval192,5
//    [51] => haval224,5
//    [52] => haval256,5
//)

The most common ones I have seen used are md5, sha1, sha256, sha384, sha512, sha3-256, and sha3-384.

There are a couple hash functions you can call by name, but most of them you have to call via the hash function.

$result = md5($some_str); // de48ff410052ff5aefa835baa0730091
$result = sha1($some_str); // 9468ed05787087ef089abd619d064ea02e1a332e
$result = hash("sha256", $some_str); // e89587cefbb65aca58b620b4b73c2414b62d434b4d3922d9d831f0eb1163acf2
$result = hash("sha384", $some_str); // 7f0085e3292ed3fa304f3e0ccc639cf566d7e4adcf716a687fdab9351a9bdbdb27d13ae10d2f6004c8f128bd0feb17e4
$result = hash("sha512", $some_str); // 66b51817cd2d70955b86de0682e73d00c592894010fc0f905687d7e09ece38dbc7de7d4fdeb99b0097453fd20358839b9ec115926ce6128e1d5e3c1be3ec169f
$result = hash("sha3-256", $some_str); // 096abe95b28240d854caa3e6563e6f7eb0252c29fd199f898f3fff145e95445a
$result = hash("sha3-384", $some_str); // e97a5337fee193fc10c86666f6d2fb5308cf0aa8b2127a2bcce1093163aa2bd4593ecf223161e45b240079b4f1a3af4e
$result = hash("sha3-512", $some_str); // 861743cc22ab78c2cc156d0f50202b828b107aa97607962428811ff450b1534202712b88fa394f75826ea73d9b46c14e9f427e54b9fc44a3235ee4e0dd2c13b9

The md5 and sha1 functions are, historically, the most common functions for message-digest hashing. The sha### and sha3-### functions are two groups, which differ mostly by the algorithm and computational complexity required.

For sha### and sha3-### functions return strings of the length ### / 8 * 2, or ### / 4. This is because they work with blocks of a bitsize equal to the number specified, and return the final block in hexadecimal format, which means every 8 bits become 2 characters.


To Conclude

So we went through a long list of functions today, we're going to use them later. The next lesson will be fun, at least I think it will be fun. We'll work with the PHP graphics API to create dynamic images.