Saturday, April 20, 2024

xdebug on Mac

…asdf

I'm using WAMP on my Windows PC, so I wanted something similar on my Mac. The most recommended stack i XAMPP and I was evaluating it for my PC as well, so I didn't look much further.

What I didn't know at that time and still amazes me is Apache and PHP are actually present in standard MacOS! So you basically only need to enable and configure them, plus install MySQL or MariaDB. With this knowledge some steps started making sense, because they're all about pointing to the “right” (XAMPP) version of PHP.

Open Terminal

Ensure XAMPP's PHP is being used. Modify your PATH to prioritize the PHP installation from XAMPP:

  1. export PATH="/Applications/XAMPP/xamppfiles/bin:$PATH"

This step is necessary for phpize command to work. I originally skipped it and then I got command not found: phpize error.

check php version

  1. php -v

apple silicon

  1. brew install autoconf automake libtool

add path

  1. arch -x86_64 sudo pecl install xdebug

asdf

download and prepare xdebug

  1. git clone https://github.com/xdebug/xdebug.git cd xdebug phpize

Configure and compile Xdebug:

  1. ./configure --with-php-config=/Applications/XAMPP/xamppfiles/bin/php-config make sudo make install

asdf

  1. nano /Applications/XAMPP/xamppfiles/etc/php.ini

asdfas

  1. [xdebug] zend_extension="/Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-<php-version>/xdebug.so" xdebug.mode=debug xdebug.start_with_request=yes xdebug.client_host=localhost xdebug.client_port=9003

asdf

  1. sudo /Applications/XAMPP/xamppfiles/bin/apachectl restart

asdf

Verify the installation. Create a phpinfo.php file in your web root directory with the following content:

  1. <?php phpinfo(); ?>

Access this file via your web browser (e.g., http://localhost/phpinfo.php) and look for the Xdebug section to confirm it is loaded correctly.

Tuesday, April 5, 2022

Error handling in PHP

asdfasd

  1. $self = $this; // To use $this in closures
  2. set_error_handler(function ($en, $es, $ef, $el) use ($self) {
  3.     $self->error("Error #".$en, $es." (".$ef.":".$el.")");
  4. });
  5. set_exception_handler(function ($ex) use ($self) {
  6.     $self->error(get_class($ex), $ex->getMessage()." in ".$ex->getFile()." on line ".$ex->getLine(), $ex->getTrace());
  7. });

asdf

  1. private function error(string $heading, string $message = "", array $trace = null) { http_response_code(500); if ($_SERVER["HTTP_ACCEPT"] === "application/json") {
  2. exit($this->json([
  3. "status" => "error",
  4. "message" => $message,
  5. "trace" => $trace ?? debug_backtrace(0)
  6. ]));
  7. }
  8. $sTrace = ""; foreach ($trace ?? debug_backtrace(0) as $i => $exl) {
  9. if (isset($exl["file"])) {
  10. $sTrace .= "\n#".$i." ".$exl["file"]."(".$exl["line"]."): ".($exl["type"] ?? "").$exl["function"];
  11. }
  12. } exit("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>".$heading."</title><link rel=\"stylesheet\" href=\"error.css\"></head><body><h1>".$heading."</h1><p>".$message."</p><pre>".$sTrace."</pre></body></html>"); }

The produced trace string could look like this:

  1. #0 D:\Dev\PHP\quid\quid.php(170): ->error #1 D:\Dev\PHP\quid\tests\trace.php(99): ->{closure} #2 D:\Dev\PHP\quid\quid.php(239): ->test #3 D:\Dev\PHP\quid\quid.php(72): ->__construct

source code using $lines = file($errFile), I did further optimizations for certain scenarios, like with PDOException I don't need to see the code for get/set method in the PDO service, but rather where the query has been constructed. For this I simply iterate over stack trace and show first script, that differs from the last one. This obviously wouldn't work properly in other scenarios, so you should adjust the behavior to your situation.

asdf

<wbr> HTML element for breaking long paths on slashes

asdf

XDebug, breakpoints

  1. if ($this->debug && function_exists("xdebug_break")) {
  2. ("xdebug_break")(); // Intelephpsense error workaround
  3. }

doesn't work properly in set_error_handler, because the calls stacks starts there, not in the code that threw the exception.

asdf

Use master try-catch and try not use local, especially if it's silent. You will probably never know about the problem. If you use local, you should rethrow the exception.

Monday, November 18, 2019

PHP templates

I've always knew PHP started as a templating engine and in its core it still is one. When I tried to figure out an easy way for implementing templates for HTML pages, I remembered this and looked around for such solutions.

I totally forgot PHP allows to mix HTML and PHP so effortlessly:

  1. <?php if (...) { ?>
  2. Hello, world!
  3. <?php } ?>

If you don't want PHP in your template, all you have to do is create some semantic markup, that you can easily replace with PHP code:

  1. {{ IF XXX }}
  2. Hello, world!
  3. {{ END IF }}

Then you generate a PHP script from your markup-flavored HTML template and keep it as cache, that changes only if you change the template. It's much faster, because you don't parse it all the time and you can even take advantage of OPcache.

For generating the PHP script you can use regular expressions, but simple explode works equally well:

  1. $ifs = explode("{{ IF ", $template);
  2. foreach ($ifs as $if) {
  3. $cond = explode("}}", $if, 2)[0];
  4. }

In the code above I separated the entire template by {{ IF and then every element again by }}. Now I have the condition I can evaluate. But I never use eval, not even for hardcoded strings. I either implement some custom condition handling, or keep it as a piece of valid PHP code.

Saturday, April 22, 2017

Type Helpers

Starting with PHP 7, a lot of things in PHP moved towards more mature programming language. But what probably will remain for a long time is function inconsistency, argument-wise.

String functions are often [haystack,needle] or [string,param], whilst array functions are often the other way around - [needle,haystack] or [param,array]. I wrote “often”, because sometimes it's not the case. What a mess!

So I decided to provide common type classes with unified order and pull some functions from Util class, where they didn't belong in the first place. I agree a need for Util classes often means wrong class architecture.

Those classes are QS, QN, QA, QD and QE for string, number, array, date and enum functions/methods. They will be optional and usage will be encouraged for creating custom modules for custom projects. The core won't need them, so if you're familiar with PHP functions, those classes won't add anything into the compiler.

They are just helpers and you may use them only for what PHP is the best in – hack something working together in an hour :-)

In JS Framework there is one extra class QC, helping with components and elements.

Wednesday, June 8, 2016

Remove newlines between double quotes

When importing data by pasting them from Excel into <textarea>, or when working with delimited-text formats like CSV or TSV (tab separated values), the simplest approach is to just split it by newline character into array of lines and iterate over them.

Because you never know, what newline format you're dealing with, I'm always starting by removing \r character, keeping only \n:

  1. $str = str_replace("\r", "", trim($data));

In the example above I also trimmed out all whitespaces from the beginning and end of the string, which may be unneeded empty lines. But if the data starts with an empty column, this would damage it (shifting columns).

But this approach would fail, if any “cell” contains newline character. In such case the cell value is enclosed mostly by double quotes and CSV parsers usually deal with it. But what if you can't or don't want to use such parsers?

The regular expression below is tailored to such case. It will replace newline character by space and multiple spaces by a single space:

  1. // Find all newlines in quotation marks...
  2. preg_match_all("/\"([^\\\\\"]*(?:\\\\.[^\\\\\"]*)*)\"/m", $str, $matches, PREG_SET_ORDER, 0);
  3. // ...and replace them with spaces.
  4. foreach ($matches as $m) $str = str_replace($m[0], preg_replace("!\s+!", " ", $m[1]), $str);

Shoutout to regex101, especially for having a Code Generator.

Sunday, February 28, 2016

PHP on IIS


Monday, February 2, 2015

PHP performance

I always checked what approach in PHP would be the fastest, especially for functionality in iteration (loop). I used simple script with a timer:

  1. function test1()
  2. {
  3. $t = microtime();
  4. while ($i < 1000) {
  5. // HERE TESTED CODE
  6. ++$i;
  7. }
  8. return microtime() – $t;
  9. }

This way I tried the best approach for zero padding or type casting from string to number.

Saturday, May 24, 2014

Mind switch

Switching from PHP to Java is awesome and painful at the same time. Awesome, because I can see the cleaner code, painful, because a lot of things, that PHP (and C#) allows and I got used to it, is now harder to do and process in my head.

But it also works the other way around. Now I can see some practices in PHP are not as great (or safe) as I thought. I already learned to keep warn level up to E_NOTICE and kill’em all. That means initialize variables. It’s more code, but it’s also more predictable.

This time I turned back to PHP and I can see why the object model used to be so exaggerated – because in compiled langs doesn’t matter how many includes there are. In PHP each include takes time (I/O) and therefore you should use merged/joined/minified version in production, or even better - use OPcache.

If you try to keep the project the same across different platforms, you always should stick with the rule of Java, where each public class has it’s own source code file.