Tag: PHP

PHP: when should I use ‘self’ and when should I use ‘$this’?

In PHP, the keyword $this is used to refer to the current instance of the class, while the keyword self is used to refer to the class itself.

You should use $this when referring to instance-level properties or methods within the same class, such as when accessing a property of the current object or calling a method of the current object.

For example:

class MyClass {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function sayHello() {
        echo "Hello, my name is " . $this->name;
    }
}

$obj = new MyClass("John");
$obj->sayHello(); // output: "Hello, my name is John"

On the other hand, you should use self when referring to static properties or methods within the same class, such as when accessing a static property or calling a static method of the class.

For example:

class MyClass {
    private static $count = 0;

    public function __construct() {
        self::$count++;
    }

    public static function getCount() {
        return self::$count;
    }
}

$obj1 = new MyClass();
$obj2 = new MyClass();
echo MyClass::getCount(); // output: 2

In summary, $this is used for instance-level properties and methods, while self is used for static properties and methods.

 

PHP: How to check if a string contains a specific word?

You can check if a string contains a specific word in PHP by using the strpos() function, the preg_match() function or the str_contains() function.

Using strpos()

The strpos() function returns the position of the first occurrence of a substring in a string. If the substring is not found, it returns false. You can use this function to check if a string contains a specific word as follows:

$string = "This is a sample string.";
$word = "sample";

if (strpos($string, $word) !== false) {
    echo "The string contains the word.";
} else {
    echo "The string does not contain the word.";
}

In this example, we first define a string $string and a word $word. Then, we use the strpos() function to check if the $string contains the $word. If the $word is found in the $string, the function will return a position value that is not false, and the output will be “The string contains the word.” Otherwise, the function will return false, and the output will be “The string does not contain the word.”

Using preg_match()

The preg_match() function searches a string for a pattern and returns true if the pattern is found, and false otherwise. You can use this function to check if a string contains a specific word as follows:

$string = "This is a sample string.";
$word = "/sample/";

if (preg_match($word, $string)) {
    echo "The string contains the word.";
} else {
    echo "The string does not contain the word.";
}

Using str_contains()

The str_contains() method is available in PHP 8 and higher versions. You can use this method to check if a string contains a specific word as follows:

$string = "This is a sample string.";
$word = "sample";

if (str_contains($string, $word)) {
    echo "The string contains the word.";
} else {
    echo "The string does not contain the word.";
}

Performance Comparison

When comparing the performance of those three methods, we get the following result:

strpos()1.37e-7 seconds = 0.137 micro seconds
preg_match()1.54e-7 seconds = 0.154 micro seconds
str_contains()1.28e-7 seconds = 0.128 micro seconds

So the new method str_contains() (for PHP 8.0 or higher) is the fastest one.

For the results, the mean execution time in a loop with 1,000,000 cycles was calculated for each method.

 

Pecl: fixing “fatal error: ‘pcre2.h’ file not found”

When using pecl to install a PHP extension, I always got a “fatal error: ‘pcre2.h’ file not found” after PHP has been updated. The update was done using brew upgrade php. In my case, this happens when I try to install pcov using:

pecl install pcov

The output was:

In file included from /private/tmp/pear/temp/pcov/pcov.c:26:
/opt/homebrew/Cellar/php/8.2.2/include/php/ext/pcre/php_pcre.h:23:10: fatal error: 'pcre2.h' file not found
#include "pcre2.h"
         ^~~~~~~~~

To fix the issue, make sure you have pcre2 installed:

brew install pcre2

After this, create a symlink to the pcre2.h file:

ln -s /opt/homebrew/Cellar/pcre2/10.42/include/pcre2.h /opt/homebrew/Cellar/php/8.2.2/include/php/ext/pcre/pcre2.h

Make sure, to adjust the versions of pcre2 and php (or any other package where you got the error). In my case it’s PHP version 8.2.2 (see the error message) and pcre2 version 10.42.

After the symlink was created, the installation of pcov finished without errors:

Build process completed successfully
Installing '/opt/homebrew/Cellar/php/8.2.2/pecl/20220829/pcov.so'
install ok: channel://pecl.php.net/pcov-1.0.11
Extension pcov enabled in php.ini

Foto von Scott Rodgerson auf Unsplash.

PHP: Function utf8_decode() and utf8_encode() have been deprecated

The utf8_encode() and utf8_decode() functions in PHP are used for encoding and decoding strings between ISO-8859-1 (Latin-1) encoding and UTF-8 encoding.

While PHP’s standard library does include utf8_encode and utf8_decode functions, they are limited to converting between ISO-8859-1 (Latin-1) and UTF-8 encodings. It is important to note that these functions cannot be relied upon to detect and convert other character encodings, such as Windows-1252, UTF-16, and UTF-32, to UTF-8. Attempting to use these functions with arbitrary text can introduce bugs that may not produce any warnings or errors, but can result in unexpected and undesired outcomes.

Examples of common bugs that can occur include:

  • The Euro sign (character sequence \xE2\x82\xAC), when passed to utf8_encode function as utf8_encode("€") results in a a garbled (also called as “Mojibake”) text output of â¬.
  • The German Eszett character (ßcharacter sequence \xDF), when passed through utf8_encode("ß") results in Ã.

The utf8_encode and utf8_decode functions have been deprecated in PHP 8.2 due to their misleading function names, lack of error messages and warnings, and their inability to support character encodings other than ISO-8859-1.

As a result, using these functions in PHP 8.2 will emit a deprecation notice. It is recommended to use alternative functions or libraries that provide better support for handling different character encodings. These functions will be removed entirely in PHP 9.0, so it is important to migrate to alternative solutions as soon as possible to avoid compatibility issues in future versions of PHP.

utf8_encode('foo');

// Function utf8_encode() is deprecated in ... on line ...
uft8_decode('foo');

// Function uft8_decode() is deprecated in ... on line ...

Replacement for the deprecated functions

Instead, the PHP documentation recommends using the multibyte string functions that are part of the mbstring extension for handling multibyte encodings, including UTF-8. For example, the mb_convert_encoding() function can be used to convert strings between different character encodings, including to and from UTF-8.

Replacement for utf8_encode()

Here is an example of how to use mb_convert_encoding() to encode a string to UTF-8:

$string = "Some string with non-ASCII characters: é, ö, ü";
$utf8_string = mb_convert_encoding($string, 'UTF-8');

Replacement for utf8_decode()

And here is an example of how to use mb_convert_encoding() to decode an UTF-8 string:

$utf8_string = "Some UTF-8 encoded string: é, ö, ü";
$string = mb_convert_encoding($utf8_string, 'ISO-8859-1', 'UTF-8');

Source: https://php.watch/versions/8.2/utf8_encode-utf8_decode-deprecated

PHP: rounding a number and keeping the zeros after comma

In PHP you can use the round() method to round a double. This methods accepts a precision value as second parameter. Some examples:

echo round(3.1415926, 2); // "3.14"
echo round(3.1415926, 3); // "3.142"

When using round() on a value like 3.0000 the conversion to a string will result in just "3":

echo round(3.0000000, 2); // "3"

This is not wrong, but when you want to have a constant precision for different numbers, having an output of "3.00" is much more helpful.

To achieve this, you can use one of the following solutions.

number_format()

echo number_format(3.1415926, 2); // "3.14"

sprintf()

echo sprintf("%.2f", 3.1415926); // "3.14"

PHP: get version details from composer.json

Let’s say we have a composer.json file as follows:

{
    "name": "mixable/blog",
    "description": "mixable.blog",
    "homepage": "https://mixable.blog",
    "version": "4.0.1",
    "type": "project",
    "require": {
        "php": "^8.x",
        "vendor/package": "^4.3",
        ...
    }
}

When using this file to manage the packages of an app, it might be necessary to check for the version of your app. This is possible by using the Composer class \Composer\InstalledVersions. The class provides different methods to access the details of the projects composer.json file.

Get details about the root package

Details about the root package are available through the getRootPackage() method:

$package = \Composer\InstalledVersions::getRootPackage();

This method returns an array with the following details:

name: string
version: string
reference: string
pretty_version: string
aliases: string[]
dev: bool
install_path: string
type: string

To get the apps version, you can use:

$version = \Composer\InstalledVersions::getRootPackage()['version'];

Get details about installed packages

There is a number of methods that provide additional information about the installed packages. Some examples:

Version of an installed package

$version = \Composer\InstalledVersions::getVersion('vendor/package');

Install path of an installed package

$installPath = \Composer\InstalledVersions::getInstallPath('vendor/package');

A detailed description of all methods is available at https://getcomposer.org/doc/07-runtime.md#installed-versions.

Photo by Ilya Pavlov on Unsplash

PHP: realpath() for non-existing path

The php method realpath() can transform the string format of a path into a real path. Means, a path string like:

/Users/mathias/data/../projects/website

will become:

/Users/mathias/projects/website

But this only works, if the path really exists. For non-existing paths, this function cannot be used. To get the same functionality, the following function can be used:

/**
 * Get normalized path, like realpath() for non-existing path or file
 *
 * @param string $path path to be normalized
 * @return false|string|string[]
 */
public function normalizePath(string $path)
{
    return array_reduce(explode('/', $path), function($a, $b) {
        if ($a === null) {
            $a = "/";
        }
        if ($b === "" || $b === ".") {
            return $a;
        }
        if ($b === "..") {
            return dirname($a);
        }

        return preg_replace("/\/+/", "/", "$a/$b");
    });
}

How to ignore PHP_CodeSniffer warning: Line exceeds 120 characters;

When using codesniffer to check your code, a lot of warnings might appear when the lines are too long:

----------------------------------------------------------------------
FOUND 0 ERRORS AND 4 WARNINGS AFFECTING 4 LINES
----------------------------------------------------------------------
  73 | WARNING | Line exceeds 120 characters; contains 162 characters
  75 | WARNING | Line exceeds 120 characters; contains 124 characters
 102 | WARNING | Line exceeds 120 characters; contains 168 characters
 108 | WARNING | Line exceeds 120 characters; contains 121 characters
----------------------------------------------------------------------

To ignore those warnings, we can add // phpcs:ignore as a comment to the end of a (too long) line. For example:

<?php
$message = 'This is my extreeeeeeeeeeeeeeeeeeeeeeeeeeeeeemly long message.'; // phpcs:ignore

Another posibility is to add the comment // @codingStandardsIgnoreLine on the line in question:

<?php
$message = 'This is my extreeeeeeeeeeeeeeeeeeeeeeeeeeeeeemly long message.'; // @codingStandardsIgnoreLine

If you want to ignore the warning for multiple lines in a file, you can add the following comments around the lines:

<?php
// @codingStandardsIgnoreStart
$message = 'This is my extreeeeeeeeeeeeeeeeeeeeeeeeeeeeeemly long message.';
// @codingStandardsIgnoreEnd

Another way to ignore the “Line exceeds” warning is to use phpcs.xml file and set the rule maxLineLength to the desired value:

<rule ref="PSR2.ControlStructures.ControlStructureSpacing">
    <properties>
        <property name="maxLineLength" value="120" />
    </properties>
</rule>

It’s worth noting that while ignoring warnings can be useful in some cases, it’s generally a better practice to address the underlying issues that are causing the warnings, as they can indicate potential problems in your code.