Skip to content
Márton Polgár edited this page Jan 28, 2024 · 33 revisions

Welcome to the DiscordPHP wiki!

PHP Discorders

To get started, check out the documentation page: https://discord-php.github.io/DiscordPHP/guide

This wiki is currently Work In Progress. Content may be missing or inaccurate. Feel free to join our Discord server to get additional help.

Improvements are welcome! The wiki pages can be edited by anyone with a GitHub account. Thank you for your contribution!

Library Architecture

Event Loop

DiscordPHP is powered by ReactPHP/Event-Loop. It is important to know that $discord->run() starts the event loop and blocks the code execution until the loop is stopped.

$discord = new Discord([
    'token' => '...',
    'loop' => Loop::get() // set the Event Loop
]);

// Register event listeners before the run()
$discord->on('ready', function (Discord $discord) {
    // Code run during event loops
});

echo 'Bot started!';
// Must be placed at the bottom
$discord->run(); // This code blocks here
// Any code below here will NOT be executed until the loop is stopped.
echo 'Bot stopped!';

Many methods from event loop are useful for the Bot operation such as the addTimer() and addPeriodicTimer():

$discord->on('ready', function (Discord $discord) {
    // get the event loop
    $loop = $discord->getLoop();
    // start a 5 seconds timer to run the function
    $loop->addTimer(5, function () {
        echo 'Printed after 5 seconds!';
    });
});

Promises

As a stateful library there is mass data that needs to be processed. This requires asynchronous execution to prevent data loss and slow downs. This means that promises are required to be used for most methods that would require contact with the Discord servers. Methods are indicated if they return promises. It is usually found with the then() and done() method chain.

Read up on the usage of promises here, albeit in a JavaScript context, but the concepts carry over to PHP. DiscordPHP is powered by ReactPHP/Promise.

Promise Usage

Here is an example of sending a message in a channel, which will return a promise:

echo 'before message'.PHP_EOL;

$channel->sendMessage('my message')->then(
    function (Message $message) {
        echo 'Message sent!'.PHP_EOL;
        // Message was successfully sent, continue with execution.
    },
    function (\Exception $e) {
        echo 'Error sending message: '.$e->getMessage().PHP_EOL;
        // Message was not sent and an error occured.
    }
);

echo 'after message'.PHP_EOL;

The output from this code would be the following:

before message
after message
Message sent!

Parts

Parts represent Discord objects such as messages, guilds and channels.

Repositories

Repositories act as data containers consisting of parts. An example is a channel repository:

  • A Guild has one ChannelRepository.
  • The ChannelRepository has many Channel parts.

Creating and modifying parts must be done through the respective repository. An example is if you are modifying a channel:

  1. The channel part is modified.
  2. The channel part is saved through the repository, which sends an HTTP request to the Discord to update the object remotely, and stores the part in the local repository.

Depending on the repository endpoints, you may use the factory methods:

  • create(Part::class, ...) or $part = new Part($discord, ...) to create a Part locally
  • fetch('PART ID') to fetch a Part from Discord (GET request to Discord API)
  • save($part) to save a Part into Discord (POST or PATCH request to Discord API)
  • delete($part) or delete('PART ID') to delete a Part locally & from Discord (DELETE request to Discord API)

Additionally you may:

  • fresh($part) load or refresh a local Part from the Discord
  • freshen() refresh all Parts from the Discord

Part & Repository Life Cycle

An example of a Message Part life cycle in a Channel:

  1. BOT received Event::MESSAGE_CREATE then the Part is created with $message = new Message($discord, ...)
    1. Additionally if storeMessages option is enabled, cache locally into $channel->messages Repository
  2. A Member sends a "delete this" Message
  3. If BOT is instructed to $message->delete() or $channel->messages->delete($message), BOT will send a DELETE HTTP request to Discord API
  4. Once the HTTP request is then(), the $message is unset() from $channel->messages Repository, and done()
$discord->on(Event::MESSAGE_CREATE, function (Message $message, Discord $discord) { // 1
    if ($message->content == 'delete this') { // 2
        $message
            ->delete() // 3
            ->then(function ($deletedMessage) { // 4
                // Message is deleted, $deletedMessage is the data of cached Message
            })
            ->done();
    }
});

Closures

Not commonly encountered in PHP web development, the callable is mostly useful in DiscordPHP especially for event loops and promises. It is important to understand how it works: https://www.php.net/manual/en/functions.anonymous.php

Callable Examples

Note: The Discord $discord argument in this case is passed by the 'ready' event emitter, another callables will have its own defined parameters based on how it is called.

Function

$myVar = 'World';

function MyFunc(Discord $discord)
{
    global $myVar; // import the global variable to this function scope

    echo 'Hello ', $myVar; // prints 'Hello World'
}

$discord->on('ready', 'MyFunc'); // use the function name

Anonymous Function

$myVar = 'World';

$discord->on('ready', function (Discord $discord) use ($myVar) { // note the $myVar is copied to the function scope with use()
    echo 'Hello ', $myVar; // prints 'Hello World'
});

Variable Function

$myVar = 'World';

$myFunc = function (Discord $discord) use ($myVar) { // note the $myVar is being imported to the function scope with use()
    echo 'Hello ', $myVar; // prints 'Hello World'
};

$discord->on('ready', $myFunc); // use the variable

Method

class MyClass {
    public $myVar = 'World';

    public function myMethod(Discord $discord)
    {
        echo 'Hello ', $this->myVar; // prints 'Hello World'
    }
}

$myObject = new MyClass;

$discord->on('ready', [$myObject, 'myMethod']); // use array of the object and the method name

Static Method

class MyClass {
    public static $myVar = 'World';

    public static function myFunction(Discord $discord)
    {
        echo 'Hello ', self::$myVar; // prints 'Hello World'
    }
}

$discord->on('ready', 'MyClass::myFunction'); // use string of class and the function name