-4

I've ran into an issue with user already has more than 'max_user_connections' active connections

This happens because I use functions for the website functionality, each function contains a

$mysqli = connect();

Though at the same time, each function closes the mysqli at the end of function

mysqli_close($mysqli);

I do not want to include $mysqli as a parameter of the function, as the function is dynamic and would be tiresome to include it with each function call.

the connect() function just contains:

$mysqli = new mysqli(...);
return $mysqli;

I believe the error is thrown because the function sometimes calls itself for different executions, based on user input and pre-requisites... even though the mysqli is closed at the end of the function...

I'd like to know if there is a way of re-using a $mysqli connection sort of like in a global way...

I'm not sure whether I've explained myself fully so if you need some more information please leave a comment.

  • Yes, you can store the mysqli handle in a static class property. – Evert Sep 21 '22 at 09:23
  • @Evert can you please show me how? I'm mainly coding in a procedural/functional way, though I know the basics of OOP, I hardly know how to implement classes etc –  Sep 21 '22 at 09:26
  • 1
    If each function closes the connection… that's a big hurdle in reusing the connection… – deceze Sep 21 '22 at 09:28
  • @deceze well if it wouldn't then I'd encounter the max_user_connections error even more frequently. that's what im trying to avoid, by figuring out how to reuse mysqli in general –  Sep 21 '22 at 09:30
  • 3
    passing $mysqli as a parameter is actually the best thing that can happen to your code. a pity that you are actively refusing it – Your Common Sense Sep 21 '22 at 09:45
  • @YourCommonSense the function is designed to be reused any number of times, each time presenting a different desired output, from a user perspective, it's not ideal to always include $mysqli in each functional call, it just looks dirty and doesn't seem like the universal solution –  Sep 21 '22 at 09:47
  • 5
    not everything that looks clean is for the good. "the road to hell is paved with good intentions". A function that knows all its stuff and which **explicitly** names its parameters one calls clean. As opposed to some global magic when some resources appear out of nowhere. – Your Common Sense Sep 21 '22 at 09:53
  • @YourCommonSense appreciate the effort, but Id consider this an exception, this code will be used by a lot of people, its just not desirable to tell each user to "dont forget the mysqli variable in the function call", a function that will be called and implemented dozens or hundreds of times... and a single mysqli connection to be reused won't hurt anyone or anything, and including it each time as a parameter just seems like a bad practice for this particular case. Im not sure whether Ive explained my intentions fully, I feel like people don't really understand what im trying to acomplish here –  Sep 21 '22 at 09:58
  • @YourCommonSense it's so trivial it's like saying "dont forget to include the $zero = 0 variable as parameter... see what Im trying to say? something that could be defined in the function easily, but for some reason ure trying to say its better to always include $zero as a parameter, u know what i mean? –  Sep 21 '22 at 10:02
  • oh, in this case passing as a parameter is the only option. or you will have to tell all those people to **rename** their mysqli connection variable and rewrite their entire code to reflect that. – Your Common Sense Sep 21 '22 at 10:03
  • No, we don't really understand. Generally though: you'd want to open a mysqli connection *once* at the beginning of your script, reuse it as needed, and then it'll get closed automatically at the end of your script. There should be no need to explicitly close it, except if you have a long-running script which persists while the connection is not needed anymore. – deceze Sep 21 '22 at 10:03
  • 1
    To pass the once-opened connection around, you pretty much have these options: 1) provide a global variable which every function includes using the `global` keyword, 2) have a function that every function calls that returns the same connection (internally using `global` or `static`), 3) use a class that gets instantiated once with the connection as argument, and then each method can access the connection as instance property, 4) explicitly pass the connection to each function as argument. – deceze Sep 21 '22 at 10:06
  • @deceze Yes, you open it once. but how do you prevent max_user_connections when the function calls itself for different reasons? Ahh.. i feel desperate honestly... I dont have a kink for closeing the connection for no reason, i do it to prevent max_user_connections as I stated in the question... i m not sure whats happening here... is this a dream –  Sep 21 '22 at 10:09
  • Don't delete the question. I have already invested time in answering it. – Dharman Sep 21 '22 at 10:10
  • @Dharman sorry, I just felt like people dont know what im talking about, and we're on stackoverflow, sigh –  Sep 21 '22 at 10:12
  • 2
    I think we do know what you are talking about. I am pretty much sure we all have fallen into this trap when we were learning how to code. Once you learn proper programming practices like SOLID, DI, MVC and so on you realize that adhering to programming standards is the best way to keep your code clean. – Dharman Sep 21 '22 at 10:14
  • 1
    Why do you get `max_user_connections`? Because you have too many simultaneous users? Then your only option is to scale up your database server. **Or because you're constantly opening new connections within the same script?!** Then don't do that… – deceze Sep 21 '22 at 10:16
  • Show a more complete sample of your code that better illustrates what predicament you're supposedly in, and what you can or can't change about it. There's no inherent reason why "a function that calls itself" must end in a `max_user_connections` error. – deceze Sep 21 '22 at 10:24
  • 1
    A recursive function can still use only a single connection. There's absolutely no reason to reopen the same connection again. – Dharman Sep 21 '22 at 10:25
  • @deceze the project is way too complex to show the entirety of it, thats why i tried to formulate the question as easily as possible, im not sure what else to tell you.. imagine you have a function that pulls a value form database, then uses that value to call the very same function but a different part of, and so on, extremely difficult to explain but thats probably why theres a confusion in the first place, nevermind. ill figure it out, as always... –  Sep 21 '22 at 10:29
  • 2
    Well, again, if you passed the connection in any of the ways I mentioned above, that's no issue: `function foo($con, $arg) { ... foo($con, 42); ... }`. Or `function foo($arg) { global $con; ... foo(42); ... }` etc. Just *don't* repeatedly call a function which opens a new connection each time, period. – deceze Sep 21 '22 at 10:31

2 Answers2

2

The proper way to reuse the same object across multiple functions/classes is to use dependency injection. Together with DI container, it can take care of providing the necessary dependencies to your functions leaving them clean.

The principle of clean code demands that your functions do not have side effects and they only do what their name states. This means that you should never be using globals in your functions as that would be causing side effects. The proper way to provide data without side effects to your function is via parameters. A connection to the database is the data that is required by your function.

If your code will be used as some kind of public library, it's even more reason to keep it clean. A function cannot have surprising behaviour. The best way to reduce surprises is by having a clear function signature. This means that all dependencies are listed as parameters with their correct types, the function cannot take dynamic arguments, and the return type must be clearly specified.


When it comes to mysqli connections (or PDO for that matter which you should prefer over mysqli), the connection should only be opened once during the execution of the script. You should never need to close the connection manually.


Here's an example of clean code. Let's imagine that you need to save bookings in the database. You create a service in your model:

<?php

class BookingService
{
    public function __construct(protected mysqli $mysqli)
    {
    }

    public function saveBooking(Booking $booking)
    {
        $stmt = $this->mysqli->prepare('INSERT INTO bookings (date, surname) VALUES (?,?)');
        $stmt->execute([$booking->getDate(), $booking->getSurname()]);
    }
}

Then in your controller, you just use your service as a dependency:

class BookingController
{
    public function __construct(protected BookingService $bookingService)
    {
    }

    public function index(Request $request)
    {
        $boooking = new Booking($request->get('date'), $request->get('surname'));
        $this->bookingService->saveBooking($boooking);
    }
}

Your DI container takes care of instantiating the mysqli and BookingService class. You can only create value objects in your controller. The necessary data is passed via parameters. This makes for a very clean and understandable code. Everyone knows what each function does, there are no surprises and everything has type specified.

Dharman
  • 30,962
  • 25
  • 85
  • 135
-1

There are a number of techniques to instantiate a variable only once. This is an anti-solution. Please do not use solutions listed here!

Static variable

If you only want a variable to be instantiated the first time the function is called, you can use a static variable.

function foo(){
    static $mysqli;
    if ($mysqli === null) {
        $mysqli = connect();
    }
    // call the same function in recursive mode and the same connection will be reused
    foo();
    // do not close the connection manually!
}

This is a bad solution because your function fetches the dependency manually. You should not create functions that have side effects or multiple objectives. A function that connects should not be called from within a function that does something else. This leads to nightmarish code, which is the reason why you are having this problem now.

Using singleton

Singletons are bad for testing and for code readability. Anytime you need to change the dependency, you need to change all the places where the singleton is used. For a better explanation of why they are bad see What are drawbacks or disadvantages of singleton pattern?

Using globals

Globals are very bad for code maintainability. They are the bane of programmers since forever. It's precisely the reason why we have encapsulation and dependency injection.

Using a global would be very similar to using a static variable, except that the side effect is now global.

function foo(){
    // declare a variable as global.
    // this will instantiate the variable to null if it doesn't exist as a global yet
    global $mysqli;
    // if it's null, connect
    if ($mysqli === null) {
        $mysqli = connect();
    }
    // call the same function in recursive mode and the same connection will be reused
    foo();
    // do not close the connection manually!
    // but if you must close the connection, just set the variable back to null
}

Do not use any of the above solutions! These are examples of bad unmaintainable spaghetti code. A programmer's nightmare. This answer is only supposed to be a warning of what not to do!

Dharman
  • 30,962
  • 25
  • 85
  • 135