0

I thought this would be easy. For troubleshooting, I wish to call my _logger() function from anywhere in my application.

function _logger(?string $msg=null, int $offset=0, bool $time=false):void
{
    $d1 = debug_backtrace()[$offset+1];
    $d2 = debug_backtrace()[$offset+2];
    syslog(LOG_INFO, sprintf('_logger%s: %s::%s(%s) called by %s::%s on line %s%s', $time?'('.date("Y-m-d H:i:s").')':'', $d1['class'], $d1['function'], json_encode($d1['args']), $d2['class'], $d2['function'], $d2['line'], $msg?' | '.$msg:''));
}

First, I tried adding it to index.php. When added directly in the main body, I got a server error and either with error reporting, couldn't get any info about it (just curious, but anyone know why?). I then placed it into the closure function and it works for HTTP requests only.

<?php

use App\Kernel;

// Added my logger() function here resulted in unexplained server error.

require_once dirname(__DIR__).'/vendor/autoload_runtime.php';

return function (array $context) {
    // Added my logger() function here works
    return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
};

Then I tried adding it to to Kernal.php, and it seems to work, but must be called as \App\_logger().

<?php

declare(strict_types=1);

namespace App;

use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel
{
    use MicroKernelTrait;
}
if(!function_exists('_logger')) {
    // Added my logger() function here works but must be called as \App\_logger()
}

So, then I created a new file called _logger.php which I located in src, and it works sometimes but other times the get the below error and need to clear cache to get it working again.

<?php

declare(strict_types=1);

if(!function_exists('_logger')) {
    // Added my logger() function sometimes works but other times doesn't
}

Expected to find class "App_logger" in file "/var/www/src/_logger.php" while importing services from resource "../src/", but it was not found! Check the namespace prefix used with the resource in /var/www/config/services.yaml (which is being imported from "/var/www/src/Kernel.php"). (500 Internal Server Error)

So, I went back to locating it in Kernel.php, and all is kind of good, but would really know the correct way to add a global function and what are the implications of Symphony's caching when I tried my various approaches.

user1032531
  • 24,767
  • 68
  • 217
  • 387
  • Kind of a duplicate of https://stackoverflow.com/questions/4458837/how-to-define-global-functions-in-php But: Is there a reason you want to do it like this and not use the proper Logger class? Using global functions is quite bad practice, even for debugging. If you use the profiler, you can see a lot of details about your request, including logs https://symfony.com/doc/current/profiler.html – SkaveRat Jul 05 '22 at 19:24

1 Answers1

2

Design decisions aside, you can achieve this by overriding the namespace in the Kernal.php file:

<?php

declare(strict_types=1);

namespace App { 
  // Must use bracket notation in order to use global namespace in the same file
  // See https://www.php.net/manual/en/language.namespaces.definitionmultiple.php#example-295

  use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
  use Symfony\Component\HttpKernel\Kernel as BaseKernel;

  class Kernel extends BaseKernel
  {
      use MicroKernelTrait;
  }
}

namespace {
  // Begin the global namespace

  if(!function_exists('_logger')) {
      // Added my logger() function here works but must be called as 
  \App\_logger()
  }
}

Note: this code is untested.

Sources:

Chris Happy
  • 7,088
  • 2
  • 22
  • 49
  • 1
    Thanks Chris, I had forgotten about this way of namespacing. Never saw a reason for it until now. I tested it and it works. Still would rather expect there is a more proper way of doing this, and wonder how dump() does it. – user1032531 Jul 05 '22 at 21:31
  • @user1032531 Might be useful to look at Symfony's polyfill code under vendor/symfony. Each one has a bootstrap.php file for defining functions and then if you look at the composer.json file you will see that bootstrap.php via a files entry under the autoload section. The dump function in the var-dumper package follows the same approach. – Cerad Jul 06 '22 at 14:15