Users management php class
Whole user management system is very hard to do properly even with structural code. When you get a grasp of entire logic &amp; security nuances OOP itself takes it to the next level, because this logic will be hard to encapsulate in objects of separate concerns - session, cookies, http request and response, domain models, view models, factories, routing... potential abstraction leaks are everywhere. That said, let's take a look at your class...

From OOP perspective

Output:

This class is not concerned about output - you don't know its format (json/html) nor channel/destination (http/console/log file) - you will validate passed values against your data model, but nothing more. For example when registering new user, the response should be the same user data (withut password - not needed anymore) with user id or class specific validation errors attached like (bool) usernameConflict, (bool) emailConflict - that's it. The rest is up to clients of this class (they might not want to reveal users' emails in this indirect way)

Database:

You should separate yourself from database - it's not relevant to your application where data comes from. Use port &amp; adapter technique - interface to query methods (taking only required parameters) and its PDO implementation.

Session:

Session at this point is a global dependency and hidden structural dependency (there needs to be session_start() somewhere). Remove it from this class and return what it needs instead. It should be something that provides user id &amp; not only that. There will be other parties interested in authentication result, so return user data without password hash and other "secrets".

Handling hashes:

This is the only concern of your class: get credentials for concrete user (defined by username, email, cookie token id) and its hash signature (password hash, persistent cookie token, ...), compare result &amp; return data useful to others - beyond this class hashes should be no use to anyone. You won't have methods covering entire login and logout procedure - just a part of it.

and side-effects...

There will be also some side-effect logic in this class like possible password rehashing on algorithm's change (after succesful match), removing cookie tokens (id+hash) on mismatch, hashing token (id+token is generated outside and passed as response cookie)... etc.

Some security concerns:


After succesful login session id should be regenerated (see: session
fixation attack)
After failed login/registration - don't inform that same email is in database (mentioned in "output" section). Registering user with existing email might be handled by sending some (merge/restore) options in activation email.
Session code doesn't protect you from anything - it
all happens inside application environment (only session id goes outside). Holding user's id for authentication (in case user is deactivated/removed) is enough
Make sure that httpOnly and Secure flags are set for session-type cookies (https might be hard to setup for localhost env, but it's neccessary on remote)
All forms should be signed/marked with CSRF tokens - new session id = generate new token is most convenient approach (every form with new token doensn't add much to protection, but causes problems with multiple open tabs, back button...)
More...