diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php
index edfdef5756..01cec77b7b 100644
--- a/src/wp-admin/includes/file.php
+++ b/src/wp-admin/includes/file.php
@@ -1701,7 +1701,7 @@ function _unzip_file_pclzip( $file, $to, $needed_dirs = array() ) {
  * Copies a directory from one location to another via the WordPress Filesystem
  * Abstraction.
  *
- * Assumes that WP_Filesystem() has already been called and setup.
+ * Assumes that WP_Filesystem() has already been called and set up.
  *
  * @since 2.5.0
  *
@@ -1733,6 +1733,22 @@ function copy_dir( $from, $to, $skip_list = array() ) {
 					return new WP_Error( 'copy_failed_copy_dir', __( 'Could not copy file.' ), $to . $filename );
 				}
 			}
+			if (
+				'.php' === strtolower( substr( $filename, -4 ) ) &&
+				function_exists( 'opcache_invalidate' ) &&
+				/**
+				 * Filters whether to invalidate a file in the PHP opcache
+				 * after it is written during an upgrade.
+				 *
+				 * @since 5.4.0
+				 *
+				 * @param bool $invalidate Whether to invalidate. Default true.
+				 * @param string $filename The PHP filename that was just copied.
+				 */
+				apply_filters( 'wp_opcache_invalidate_file', true, $to . $filename )
+			) {
+				opcache_invalidate( $to . $filename );
+			}
 		} elseif ( 'd' == $fileinfo['type'] ) {
 			if ( ! $wp_filesystem->is_dir( $to . $filename ) ) {
 				if ( ! $wp_filesystem->mkdir( $to . $filename, FS_CHMOD_DIR ) ) {
diff --git a/src/wp-admin/includes/update-core.php b/src/wp-admin/includes/update-core.php
index 9dbe8bead1..fd69c38447 100644
--- a/src/wp-admin/includes/update-core.php
+++ b/src/wp-admin/includes/update-core.php
@@ -1307,11 +1307,14 @@ function update_core( $from, $to ) {
 }
 
 /**
- * Copies a directory from one location to another via the WordPress Filesystem Abstraction.
- * Assumes that WP_Filesystem() has already been called and setup.
+ * Copies a directory from one location to another via the WordPress Filesystem
+ * Abstraction.
  *
- * This is a temporary function for the 3.1 -> 3.2 upgrade, as well as for those upgrading to
- * 3.7+
+ * Assumes that WP_Filesystem() has already been called and set up.
+ *
+ * This is a standalone copy of the `copy_dir()` function that is used to
+ * upgrade the core files. It is placed here so that the version of this
+ * function from the *new* WordPress version will be called.
  *
  * @ignore
  * @since 3.2.0
@@ -1346,6 +1349,14 @@ function _copy_dir( $from, $to, $skip_list = array() ) {
 					return new WP_Error( 'copy_failed__copy_dir', __( 'Could not copy file.' ), $to . $filename );
 				}
 			}
+			if (
+				'.php' === strtolower( substr( $filename, -4 ) ) &&
+				function_exists( 'opcache_invalidate' ) &&
+				/** This filter is documented in wp-admin/includes/file.php */
+				apply_filters( 'wp_opcache_invalidate_file', true, $to . $filename )
+			) {
+				opcache_invalidate( $to . $filename );
+			}
 		} elseif ( 'd' == $fileinfo['type'] ) {
 			if ( ! $wp_filesystem->is_dir( $to . $filename ) ) {
 				if ( ! $wp_filesystem->mkdir( $to . $filename, FS_CHMOD_DIR ) ) {
