That's correct. It's controlled by the HTTP Cache-Control and Expires headers.
The first one basically tells the client the cache strategy. The second one basically tells the client the expiration time of the cache strategy (i.e. for how long to adhere the cache strategy before obtaining the new response and/or throwing the cached resposne away).
The webserver usually sends a default set of those headers. You can set/override those headers permanently in the server configuration or on a request basis in PHP using header() function. The following example instructs the client to never cache the response.
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
The Pragma header is there to ensure compatibilty with old HTTP 1.0 clients which doesn't support Cache-Control yet (which was introduced in HTTP 1.1).
When the cache has been expired and the cached response contains a Last-Modified and/or ETag header as well, then the client can fire a conditional GET request with If-Modified-Since and/or If-None-Match. Whenever the If-Modified-Since and/or If-None-Match conditions are positive, then the server will send a 304 "Not Modified" response back without any content. If this happens, then the client is allowed to keep the currently cached content in the cache and update the headers.