Verification: a143cc29221c9be0

Php class call this function

Table of contents

  • Introduction

  • MessageBoxA function (winuser.h)

  • MessageBoxA call from PHP

  • MessageBoxA class

  • MessageBoxA class example

Introduction

FFI (Foreign Function Interface) - расширение ЭКСПЕРИМЕНТАЛЬНОЕ. Модуль позволяет загружать общие (shared) библиотеки (.DLL или .so), вызывать функции на языке C и получать доступ к структурам языка C из PHP без необходимости глубоко изучать API модулей Zend и стороннего, "промежуточного" языка.

В PHP >= 7.4.0 появилось новое расширение FFI, с помощью которого можно выйти за рамки привычного PHP и использовать сторонние библиотеки. Познакомимся с этим расширением на примере HelloWorld, который будем выводить в системное окно с помощью Windows API функции MessageBoxA.

Репозиторий с полным кодом проекта: https://github.com/superrosko/example-php-ffi-windows-hello-world-msgbox.

MessageBoxA function (winuser.h)

Обратимся к документации по Windows API для того, чтобы понять, как вызывать функцию MessageBoxA.

int MessageBoxA(
  HWND   hWnd,
  LPCSTR lpText,
  LPCSTR lpCaption,
  UINT   uType
);

Видим, что функция принимает 4 параметра:

  1. hWnd (HWND) - указатель на окно, которому будет принадлежать создаваемый нами MessageBox. Мы будем передавать NULL, т.е. наш MessageBox не будет иметь владельца.

  2. lpText (LPCSTR) - указатель на текст сообщения.

  3. lpCaption (LPCSTR) - указатель на текст заголовка сообщения.

  4. uType (UINT) - дополнительные параметры окна, которые опишем константами.

Также нам нужно узнать название библиотеки, из которой мы будем вызывать MessageBox. За эту функцию отвечает библиотека User32.dll.

Теперь у нас есть вся информация для вызова MessageBox из PHP-скрипта.

MessageBoxA call from PHP

Зададим имя библиотеки и декларацию функции MessageBox. Вместо LPCSTR используем const char*, а вместо UINT используем int в определении языка C.

$lib = 'User32.dll';
$declaration = 'int MessageBoxA(int hWnd, char * lpText, char * lpCaption, int uType);';

Создадим объект FFI:

$ffi = FFI::cdef($declaration, $lib);

Вызовем созданную функцию с нужными нам параметрами:

$ffi->MessageBoxA(null, 'Hello World!!!', 'MessageBox from PHP!',0x00000040 | 0x00000001);

После выполнения скрипта на экране мы увидим MessageBox текстом Hello World!!!, заголовком окна MessageBox from PHP!, иконкой информации и двумя кнопками OK и CANCEL.

MessageBoxA class

Обернем вызовы и все константы в класс:

declare(strict_types=1);

namespace Superrosko\ExamplePhpFFI\WindowsApi;

use FFI;


class MessageBoxA
{
    
    const MB_ABORTRETRYIGNORE = 0x00000002; 
    const MB_CANCELTRYCONTINUE = 0x00000006; 
    const MB_HELP = 0x00004000; 
    const MB_OK = 0x00000000; 
    const MB_OKCANCEL = 0x00000001; 
    const MB_RETRYCANCEL = 0x00000005; 
    const MB_YESNO = 0x00000004; 
    const MB_YESNOCANCEL = 0x00000003; 

    
    const MB_ICONEXCLAMATION = 0x00000030; 
    const MB_ICONWARNING = 0x00000030; 
    const MB_ICONINFORMATION = 0x00000040; 
    const MB_ICONASTERISK = 0x00000040; 
    const MB_ICONQUESTION = 0x00000020; 
    const MB_ICONSTOP = 0x00000010; 
    const MB_ICONERROR = 0x00000010; 
    const MB_ICONHAND = 0x00000010; 

    
    const MB_DEFBUTTON1 = 0x00000000; 
    const MB_DEFBUTTON2 = 0x00000100; 
    const MB_DEFBUTTON3 = 0x00000200; 
    const MB_DEFBUTTON4 = 0x00000300; 

    
    const MB_APPLMODAL = 0x00000000;
    const MB_SYSTEMMODAL = 0x00001000;
    const MB_TASKMODAL = 0x00002000;

    
    const MB_DEFAULT_DESKTOP_ONLY = 0x00020000; 
    const MB_RIGHT = 0x00080000; 
    const MB_RTLREADING = 0x00100000; 
    const MB_SETFOREGROUND = 0x00010000; 
    const MB_TOPMOST = 0x00040000; 
    const MB_SERVICE_NOTIFICATION = 0x00200000; 

    
    const IDOK = 1; 
    const IDCANCEL = 2; 
    const IDABORT = 3; 
    const IDRETRY = 4; 
    const IDIGNORE = 5; 
    const IDYES = 6; 
    const IDNO = 7; 
    const IDCLOSE = 8;
    const IDHELP = 9;
    const IDTRYAGAIN = 10; 
    const IDCONTINUE = 11; 

    
    private string $lib = 'User32.dll';

    
    private string $declaration = 'int MessageBoxA(int hWnd, char * lpText, char * lpCaption, int uType);';

    
    public function __construct(
        private ?int $hWnd,
        private string $lpText,
        private ?string $lpCaption,
        private int $uType
    ) {
    }

    
    public static function init(
        ?int $hWnd,
        string $lpText,
        ?string $lpCaption,
        int $uType
    ): MessageBoxA {
        return new self($hWnd, $lpText, $lpCaption, $uType);
    }

    
    public function call(): int
    {
        
        $ffi = FFI::cdef($this->declaration, $this->lib);

        
        return (int) $ffi->MessageBoxA(
            $this->hWnd,
            $this->lpText,
            $this->lpCaption,
            $this->uType);
    }
}

Prefab

Если вы хотите, чтобы один из ваших классов был синглтоном(гарантирующим, что в однопоточном приложении будет единственный экземпляр некоторого класса), просто расширьте класс Prefab:

class MyClass extends \Prefab {
 
  private $year;
 
  function getYear() {
    return $this->year;
  }
 
  function __construct() {
    $this->year=date('Y');
  }
}

Таким образом, класс будет создан не более одного раза. Чтобы получить синглтон, используйте статический метод instance():

// somewhere in the code
$obj=MyClass::instance(); // First call: a new object is created
echo $obj->getYear();
 
// somewhere else in the code
$obj=MyClass::instance(); // Second call: the object already exists and is simply returned
echo $obj->getYear();

Большинство классов F3 (Base, Cache, View, Template, Web и т. Д.) являются производными от Prefab

Registry

Каждый отдельный объект хранится в реестре. Реестр принимает несколько команд:

get

Получить объект из реестра

$obj=\Registry::get('MyClass');

set

Сохранить объект в реестре

$obj=new MyClass();
\Registry::set('MyClass',$obj);

clear

Удалить объект из реестра

\Registry::clear('MyClass');

exists

Проверить, хранится ли объект в реестре

if (\Registry::exists('MyClass'))
  echo 'Singleton instanciated';
else
  echo 'Singleton not instanciated';