Pulling In and Referencing Other Files
Include and Require Method Calls
- Include
- Require (identical signatures to above)
WARNING: Avoid using relative paths whenever possible. A common approach (example) is to define constants / globals that hold absolute paths that can be shared across your environment, so you don't always have to do a lookup with
dirname(__FILE__)
all the time.
NOTE: For both
include
andrequire
, parenthesis around file name are not required, nor recommended.
Include vs Require
Short answer: require
will throw a fatal error (halt execution) if it can't load the file, whereas include
will not.
Echoing out JavaScript, CSS, and other Text
If you have a local file, such as a JavaScript .js
file, that you simply want to echo out into the page, you can use echo file_get_contents()
or the readfile()
function.
For example:
<?php echo file_get_contents($jsDirPath . '/myJsFile.js'); ?>
Echoing Out or Returning HTML
One of the things that is both really fun about PHP, as well as strange, is the way it interfaces directly with HTML and sending content to the browser "over the wire". There are many different ways to return HTML content from PHP, starting with simply stopping and starting the interpretation of PHP with PHP tags.
<?php
$test = 123;
// Stopping PHP...
?>
<div> Hello from HTML! </div>
<?php
// Resuming PHP
?>
You can also use the short echo tag to pause and resume PHP:
<?= 'this will echo' ?>
However, this is not the only way to echo out HTML, and more importantly, it doesn't allow us to capture the resulting HTML as a string instead of echoing out. For that, we need to look to other solutions.
A handy solution in PHP for this is output buffering. This lets you send all output from the current script into a buffer, then capture the value of that buffer as a string and do whatever you want with it (return it from a function, pass it around, etc.).
Buffering Output Example
<?php
function generateButtonsHtml(int $count) {
$done = 1;
ob_start();
while ($done < $count + 1) {
?>
<button id="button-<?= $done ?>"> Button #<?= $done ?></button>
<?php
$done++;
}
$htmlStr = ob_get_clean();
return $htmlStr;
}
$count = isset($_GET['count']) ? intval($_GET['count']) : 1;
echo generateButtonsHtml($count);
For general alternative approaches to building up / wrapping strings, you should check out this StackOverflow answer.
Echoing Out or Returning JSON
There are two main steps to returning JSON.
- If you are building an API, or something that is returning the JSON as the only response within the network request, then you should set the
content-type
header:header('Content-type: application/json');
- For actually echoing out the JSON, there are multiple options
- If you have a PHP object, and want to return it as JSON, use
echo json_encode($myPhpObj)
- If you have the JSON as a raw string, you can simply echo it
- If you want to paste JSON into a PHP file to echo back out later, you can use the Heredoc / Nowdoc syntax to avoid having to escape line breaks or special characters
- If you have a PHP object, and want to return it as JSON, use
Strings
Instantiating and Escaping Complex or Multi-Line Strings
If you have a really long string literal that spans multiple lines, and/or contains a lot of characters that would need to be escaped, a handy tool to use is the Heredoc syntax (or Nowdoc).
The safest usage, if you don't need variable replacement, is the Nowdoc syntax:
$myStr = <<<'EOD'
Hello World
On the second line
Final line!
EOD;
Heredoc is also a close replacement for JavaScript's backticks / template literal strings.
How do I...
- Initialize an array:
- Simple (numerical indexed):
$myArr = array("alpha", "bravo");
- Associative:
$myArr = array( "primaryColor" => "red", "secondaryColor" => "blue" ); // Or, with v > 5.4 $myArr = [ "primaryColor" => "red", "secondaryColor" => "blue" ];
- Simple (numerical indexed):
- Add to an array
array_push($myArr, $valToPush);
- Get the length of something
- String:
strlen($myStr);
- Array:
count($myArr);
- String:
- Use types
- Type annotation has been unofficially supported through PHPDoc and IDEs
/** @var string $myStr */
- Official type support (including run-time checks) were added in PHP 5, and given a major expansion in v7.
function testBool(bool $input) {}
- Type annotation has been unofficially supported through PHPDoc and IDEs
- Use default values in function arguments
- See Docs
- General rules:
- Default value must be constant value, not variable or function call
- Default args / values should always come last
- Safely check variables without throwing
undefined
errors?empty()
orisset()
seem to be the only two ways to safely check for defined.- Things like
gettype()
or equality checks will emit errors if the variable is undefined- E.g.: You cannot do
if ($_POST['myPostKey']) {}
as it will throw aUndefined index
error
- E.g.: You cannot do
- Suppress errors
- It almost goes without saying that errors shouldn't be ignored; best option is try / catch, log properly, etc.
- However, if you really do need to suppress, PHP has a call syntax - prefix command with
@
, which is an error control operator
- Get a PHP REPL
- PHP CLI, with
-a
flag for interactive shell (php -a
) (docs)
- PHP CLI, with
Objects
The PHP manual has a good guide on objects in PHP.
Instantiating Objects in PHP
There are multiple options for how to instantiate an "object" in PHP.
- Option: Create a class with public members, and call with
new
class MyClass { public $primaryColor = 'red'; } $myObj = new MyClass();
- Option: Cast an associative array to an object:
$myObj = (object) array( 'primaryColor' => 'red' );
- Internally, this is basically the same as creating a
stdClass
instance - Downside: You might lose Intellisense / autocomplete on
$myObj
, especially in VSCode
- Internally, this is basically the same as creating a
For creating an empty object (for example, as a bucket for future values), you can use the methods above, but in a streamlined way:
- You can use
$emptyObj = new stdClass();
- You can use
$emptyObj = (object) [];
Traits
https://www.php.net/manual/en/language.oop5.traits.php
Kinda similar to TS interfaces. Allows you to reuse methods declared in trait, in a class, without extending (bypass PHP's "no multiple inheritance" rule)
Important notes:
- Traits are not just declarations; they (can) include the whole implementation
- A function declared in a class using a trait, with the same name as a function in the trait, will override that function
- HOWEVER, if two traits try to override the same method: a fatal error is produced, if the conflict is not explicitly resolved
- To resolve, make sure you use
MyTraitA::myMethod instead of B
- To resolve, make sure you use
- HOWEVER, if two traits try to override the same method: a fatal error is produced, if the conflict is not explicitly resolved
- Within trait functions you can use
parent::
- Syntax is
use MyTrait
as first line below class opening brace, to use trait
VSCode
PHP, like some other languages out there, has a user-base that has been kind of slow to adopt VSCode as an IDE. As a bit of a self-fulfilling prophecy (why build something if no one is going to use it?), PHP support in VSCode is a little lackluster (at least at the moment).
In general, the PHP community tends to use software from the JetBrains company; particularly PhpStorm. To be fair to PHP devs, PhpStorm has been around since 2009, while VSCode has only been around since 2015.
WordPress Editing in VSCode
I recommend either:
- Edit your theme / plugin by opening an entire Wordpress installation directory (i.e., the root folder that contains
wp-config.php
), so VSCode can pick up the function declarations- And / Or...
- Install the
WordPress Snippets
extension
Formatting PHP in VSCode
One of the most popular extensions for PHP in VSCode is PHP Intelephense by Ben Mewburn. This can function as a formatter, but it has limited controls when it comes to that (for example, disabling Allman braces is not yet an option).
For strong coding standards enforcement, you probably want to be using PHP CodeSniffer (aka phpcs). It can be used as a standalone CLI tool, but there is also a VSCode extension for linting, as well as one that handles both linting and auto-formatting, called PHP Sniffer & Beautifier (aka PHPSAB)
Another alternative is phpfmt - PHP formatter. Although it is no longer maintained (😢), it is one of the few PHP formatting extensions that does not require PHPCS as a dependency. If you want to default to K&R style braces instead of Allman, you can use these settings.
If you run into issues using PHPSAB in a multi-root setup, you might want to try hard-coding any setting that takes a path, with absolute paths, not relative paths. For example, the
phpsab.executablePathCS
andphpsab.executablePathCBF
settings.
Linting and Formatting
PHP CodeSniffer
Github page: squizlabs/PHP_CodeSniffer
- How to use config file /
phpcs.xml
?- Intro docs are here, and here are the ruleset docs
PHPCS - Issues
One issue I ran into PHPCS, or at least with the auto-fixer + PHPCS, was around the spacing and alignment of comments. I kept getting Found precision alignment of 1 spaces.
mixed with Expected 2 space(s) before asterisk; 1 found
as the linting error, but the auto-fixer would also seem to get stuck and not touch the file.
Comment Spacing Issue
This issue of the auto-fixer getting stuck seems to be caused by when you start with this input:
/**
* My Comment
*/
then run the fixer, it turns into:
/**
* My Comment
*/
Which it has no clue how to fix and does not attempt to. However, if you MANUALLY make sure FIRST line has no leading space, it will pass and even fix if lower lines are off. For example, input:
/**
* My Comment
*/
Auto-fixed, passes lint:
/**
* My Comment
*/
Debugging
XDebug
XDebug is the best solution. Usually all it takes to enable is to download the matching DLL (use this tool to find matching version) and place in extension folder. Then add these lines to php.ini
config file (example):
zend_extension=xdebug-2.7.2-7.2-vc15-x86_64
xdebug.remote_enable=1
xdebug.remote_autostart=1
In VSCode, you will need an extension to enable PHP debugging - I recommend the PHP Debug Adapter by Becker. this is usually the config I use in launch.json
for debugging:
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9003
}
Warning: Adding XDebug will usually add some additional load time in your local environment
I believe past versions of XDebug used port
9000
- default is now9003
Manually triggering XDebug
Aside from adding breakpoints, you can also trigger your IDE debugger manually (similar to JavaScript debugger;
kw), by using xdebug_break()
(details). Just make sure to not have in production code!!!
Profiling with XDebug
Follow the official guide.
Sample php.ini
settings:
xdebug.profiler_enable=1
xdebug.mode=profile
xdebug.output_dir="C:/Users/Joshua/AppData/Local/Temp/xdebug_prof"
For profile viewing, WinCacheGrind was easy to use on Windows.
VSCode PHP Debugging - Ignoring Files
If you are using lots of PHP tooling, you might run into the issue that your local dev tooling (unrelated to the runtime of what you are actually building) is triggering the VSCode debugger extension.
For example, I first encountered this with phpcs / code_sniffer throwing exceptions while linting open files. If I had an open stack-trace and then switched tab, the linter would interrupt the debugging process and inject a new stack trace (very annoying!).
If you are using the popular PHP debug adapter extension, the way around this is to tell the extension to ignore certain file patterns while running a debug session. You can do this with ignore: []
under your specific launch configuration. E.g.:
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"ignore": ["**/vendor/**/*.php"]
},
For the full list of
launch.json
settings, make sure to check out the docs for PHP Debug.
Type Annotations / Comments
In general, support for type annotations through comments generally depends on the IDE you are using and/or installed extensions. However, The general accepted standard is PHPDoc
, as opposed to alternatives. Here is the PHPDoc Reference Page.
Here are some extra tricks for using PHPDoc:
- If you are using
intelephense
with VSCode, you can check out intelephense-docs - Although you cannot document things like
stdclass
inline, you can add PHP files that are strictly for annotating structures and don't actually do anything at run-time - If you are trying to use types within a namespaced file, you will need to prefix the type with
/
to avoid the doc interpreter from thinking the type belongs to the current namespace. E.g.@param \WP_POST $post
instead of@param WP_POST $post
As of right now (09/13/2020), there is no option to ignore single errors / type issues with
intelephense
. See Issue #568.